Bisakah saya memberikan default untuk gabungan luar kiri?

21

Misalkan saya memiliki tabel a (dengan kolom a1) dan b (dengan kolom b1 dan b2) dan saya melakukan gabungan luar kiri

SELECT *
FROM a LEFT OUTER JOIN b
ON a.a1 = b.b1

Kemudian b1 dan b2 akan menjadi NULL di mana nilai a1 tidak memiliki nilai yang cocok dengan b1.

Bisakah saya memberikan nilai default untuk b2, bukan NULL? Perhatikan bahwa Bersatu tidak akan bekerja di sini, karena saya tidak ingin nilai default untuk menimpa potensi NULLs di b2 di mana ada adalah nilai a1 pencocokan b1.

Yaitu, dengan a dan b sebagai

CREATE TABLE a (a1)
  AS VALUES (1),
            (2),
            (3) ;

CREATE TABLE b (b1,b2)
  AS VALUES (1, 10),
            (3, null) ;


a1     b1 | b2
---    --------
 1      1 | 10
 2      3 | NULL
 3

dan default untuk b2 dari, katakanlah, 100, saya ingin mendapatkan hasilnya

a1 | b1   | b2
---------------
1  |  1   | 10
2  | NULL | 100
3  |  3   | NULL

Dalam kasus sederhana ini saya bisa melakukannya "dengan tangan" dengan melihat apakah b1 NULL dalam output. Apakah itu pilihan terbaik secara umum, atau ada cara yang lebih standar dan lebih rapi?

Tom Ellis
sumber

Jawaban:

23
SELECT a.a1,b.b1,  
    CASE WHEN b.b1 is NULL THEN 5 ELSE b.b2 END AS b2  
FROM a LEFT OUTER JOIN b  
ON a.a1 = b.b1
Mordechai
sumber
2
Silakan gunakan ANSI SQL ketika pertanyaan hanya ditandai dengan sql(yang berarti "SQL the query language". Tag itu tidak menunjukkan produk atau dialek DBMS tertentu). Bagian: [b2]=CASE WHEN ... ENDadalah ekspresi SQL yang tidak valid (standar).
a_horse_with_no_name
Saya telah menambahkan tag untuk menunjukkan bahwa saya akan menerima jawaban spesifik Postgres. Namun, SQL standar akan lebih disukai jika memungkinkan.
Tom Ellis
@ Kin: seperti yang dinyatakan dalam pertanyaan saya, saya tahu bahwa "saya bisa melakukannya" dengan tangan "dengan melihat apakah b1 adalah NULL dalam output. Apakah itu pilihan terbaik secara umum, atau apakah ada cara yang lebih standar dan lebih rapi?"
Tom Ellis
3
karena Anda ingin membedakan antara NULL yang terjadi karena GABUNG dan yang "hadir secara alami", tidak dapat dihindari bahwa Anda harus memeriksa b1. Jika itu yang Anda maksud dengan "Saya bisa melakukannya" dengan tangan "", daripada ya, itulah satu-satunya cara.
Mordechai
@MorDeror: Oke, saya kira saya berpikir mungkin ada sintaksis seperti "LEFT OUTER JOIN ... ON ... DEFAULT b2 = ...".
Tom Ellis
2

Jawaban asli untuk pertanyaan ini tidak dapat dijelaskan, jadi mari kita coba lagi.

Menggunakan CASEpernyataan

Dengan menggunakan metode ini, kami mengeksploitasi bahwa kami memiliki nilai lain di kolom berbeda yangIS NOT NULL dalam hal ini b.b1jika nilai itu nol, maka kami tahu bahwa gabungan gagal.

SELECT
  a.a1,
  b.b1,  
  CASE WHEN b.b1 is NULL THEN 100 ELSE b.b2 END AS b2  
FROM a
LEFT OUTER JOIN b  
  ON (a.a1 = b.b1);

Ini benar-benar akan berfungsi, dan menghasilkan hal yang persis Anda inginkan.

Menggunakan sub-SELECT

Jangan gunakan metode ini, itu ide yang membangun. Teruslah membaca.

Jika kita tidak memiliki NOT NULLkolom apa pun yang dapat kita manfaatkan seperti itu, kita perlu sesuatu untuk membuat kolom yang dapat berfungsi seperti itu bagi kita ...

SELECT
  a.a1,
  b.b1,  
  CASE WHEN b.cond IS NULL THEN 100 ELSE b.b2 END AS b2  
FROM a
LEFT OUTER JOIN (
  SELECT true AS cond, b.*
  FROM b
) AS b
  ON (a.a1 = b.b1);

Menggunakan perbandingan baris

Lebih mudah lagi jika kemudian memaksakan nilai palsu yang dapat kita bandingkan, adalah membandingkan baris. Di PostgreSQL, baris memiliki nilai berdasarkan nama tabel. Misalnya, SELECT foo FROM foomengembalikan baris tipe foo(yang merupakan tipe baris), dari tabel foo. Di sini kami menguji untuk melihat apakah ROW itu nol. Ini akan bekerja selama setiap kolom IS NOT NULL. Dan, jika setiap kolom IS NULLdi meja Anda, maka Anda hanya trolling.

SELECT
  a.a1,
  b.b1,  
  CASE WHEN b IS NULL THEN 100 ELSE b.b2 END AS b2  
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);
Evan Carroll
sumber
Kolom yang b1digunakan dalam CASEsolusi tidak harus non-nullable. Konstruksi bekerja dalam kedua kasus.
ypercubeᵀᴹ
1

Saya menemukan COALESCE sangat berguna dalam kasus itu. Ini akan mengembalikan nilai NULL pertama dari daftar:

SELECT
 a.a1,
 b.b1,
 COALESCE (b.b2, 100) AS b2
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);
rampok
sumber