Czy mogę podać domyślny lewy łącznik zewnętrzny?

21

Załóżmy, że mam tabele a (z kolumną a1) ib (z kolumnami b1 i b2) i wykonuję lewe łączenie zewnętrzne

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

Wtedy b1 i b2 będą miały wartość NULL, gdzie wartość a1 nie ma pasującej wartości b1.

Czy mogę podać wartość domyślną dla b2 zamiast NULL? Zauważ, że COALESCE nie będzie działać tutaj, bo nie chcę, aby zastąpić domyślną wartość potencjalnych wartości null w b2 gdzie jest wartość b1 dopasowania A1.

To znaczy, z aib jako

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

i domyślnie dla b2, powiedzmy 100, chcę uzyskać wynik

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

W tym prostym przypadku mógłbym to zrobić „ręcznie”, sprawdzając, czy b1 ma wartość NULL na wyjściu. Czy to ogólnie najlepsza opcja, czy może jest to bardziej standardowy i bardziej uporządkowany sposób?

Tom Ellis
źródło

Odpowiedzi:

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
Mordechaj
źródło
2
Proszę użyć ANSI SQL, gdy pytanie jest tylko oznaczone sql(co oznacza „SQL język zapytań”. Ten znacznik nie oznacza żadnego konkretnego produktu DBMS ani dialektu). Część: [b2]=CASE WHEN ... ENDjest niepoprawnym (standardowym) wyrażeniem SQL.
a_horse_w_no_name
Dodałem tag wskazujący, że zaakceptuję odpowiedź Postgres. Mimo to preferowany jest standardowy SQL, jeśli to możliwe.
Tom Ellis,
@Kin: jak stwierdzono w moim pytaniu, wiem, że „mógłbym to zrobić” ręcznie, sprawdzając, czy b1 ma wartość NULL na wyjściu. Czy jest to ogólnie najlepsza opcja, czy też jest bardziej standardowy i bardziej uporządkowany sposób? ”
Tom Ellis,
3
skoro chcesz rozróżnić NULL-y, które występują z powodu JOIN, i te, które są „naturalnie” obecne, nieuniknione jest, że będziesz musiał zbadać b1. Jeśli to miałeś na myśli mówiąc „mógłbym to zrobić ręcznie”, niż tak, to jedyny sposób.
Mordechai
@ MorDeror: OK, przypuszczam, że myślałem, że może istnieć składnia, taka jak: „POŁĄCZ ZEWNĘTRZNE DOŁĄCZENIE… ON… DOMYŚLNE b2 =…”.
Tom Ellis,
2

Oryginalna odpowiedź na to pytanie nie została wyjaśniona, więc dajmy to jeszcze raz.

Za pomocą CASEoświadczenia

Korzystając z tej metody, wykorzystujemy to ,IS NOT NULL że mamy inną wartość w innej kolumnie, która w tym przypadku, b.b1jeśli ta wartość jest pusta, to wiemy, że połączenie nie powiodło się.

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);

To całkowicie zadziała i wygeneruje dokładnie to, czego chcesz.

Korzystanie z podselekcji

Nie używaj tej metody, to pomysł na rozbudowę. Czytaj dalej.

Jeśli nie mamy żadnych NOT NULLkolumn, które moglibyśmy wykorzystać w ten sposób, potrzebujemy czegoś, aby stworzyć kolumnę, która mogłaby dla nas działać w ten sposób ...

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);

Korzystanie z porównania wierszy

Jeszcze łatwiejsze niż wymuszanie fałszywej wartości, dla której możemy porównać, jest porównanie wiersza. W PostgreSQL wiersz ma wartość według nazwy tabeli. Na przykład SELECT foo FROM foozwraca wiersz typu foo(który jest typem wiersza) z tabeli foo. Tutaj sprawdzamy, czy ten ROW jest zerowy. Będzie to działać tak długo, jak każda kolumna IS NOT NULL. A jeśli każda kolumna IS NULLw tabeli, to po prostu trollujesz.

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
źródło
Kolumna b1użyta w CASEroztworze nie musi mieć wartości zerowej. Budowa działa w obu przypadkach.
ypercubeᵀᴹ
1

W tym przypadku uważam, że COALESCE jest bardzo przydatny. Zwróci pierwszą wartość inną niż NULL z listy:

SELECT
 a.a1,
 b.b1,
 COALESCE (b.b2, 100) AS b2
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);
Obrabować
źródło