Posso fornire un valore predefinito per un join esterno sinistro?


21

Supponiamo che io abbia le tabelle a (con la colonna a1) e b (con le colonne b1 e b2) e eseguo un join esterno sinistro

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

Quindi b1 e b2 saranno NULL dove un valore di a1 non ha valore corrispondente di b1.

Posso fornire un valore predefinito per b2, anziché NULL? Si noti che COALESCE non funziona qui, perché io non voglio che il valore di default per ignorare i potenziali NULL in b2 in cui v'è un valore di b1 a1 corrispondenza.

Cioè, con a e b come

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

e un valore predefinito per b2, diciamo, 100, voglio ottenere il risultato

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

In questo semplice caso ho potuto farlo "a mano" osservando se b1 è NULL nell'output. È l'opzione migliore in generale o esiste un modo più standard e ordinato?

Risposte:


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

2
Si prega di utilizzare ANSI SQL quando la domanda è taggata solo con sql(che significa "SQL il linguaggio delle query". Quel tag non indica alcun prodotto o dialetto DBMS specifico). La parte: [b2]=CASE WHEN ... ENDè un'espressione SQL (standard) non valida.
a_horse_with_no_name

Ho aggiunto un tag per indicare che accetterei una risposta specifica per Postgres. Tuttavia, SQL standard sarebbe preferito se possibile.
Tom Ellis,

@Kin: come affermato nella mia domanda, so che "Potrei farlo" a mano "osservando se b1 è NULL nell'output. È l'opzione migliore in generale o esiste un modo più standard e più ordinato?"
Tom Ellis,

3
poiché vuoi distinguere tra i NULL che si verificano a causa di un JOIN e quelli che sono "naturalmente" presenti, è inevitabile che tu debba esaminare b1. Se questo è ciò che intendevi per "potrei farlo" a mano "", allora sì, questo è l'unico modo.
Mordechai,

@MorDeror: OK, suppongo che stavo pensando che potrebbe esserci una sintassi come "LEFT OUTER JOIN ... ON ... DEFAULT b2 = ...".
Tom Ellis,

2

La risposta originale a questa domanda non è stata spiegata, quindi diamo un'altra possibilità.

Usando una CASEdichiarazione

Usando questo metodo sfruttiamo che abbiamo un altro valore in una colonna diversa cheIS NOT NULL in questo caso b.b1se quel valore è nullo allora sappiamo che l'unione non è riuscita.

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

Questo funzionerà totalmente e genererà esattamente ciò che desideri.

Usando un sub-SELECT

Non usare questo metodo, è un'idea di accumulo. Continua a leggere.

Se non abbiamo NOT NULLcolonne che possiamo sfruttare in questo modo, abbiamo bisogno di qualcosa per creare una colonna che possa funzionare in quel modo per noi ...

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

Utilizzando un confronto di righe

Ancora più semplice, quindi forzare un valore falso per il quale possiamo confrontare, è confrontare la riga. In PostgreSQL, la riga ha un valore in base al nome della tabella. Ad esempio, SELECT foo FROM foorestituisce una riga di tipo foo(che è un tipo di riga), dalla tabella foo. Qui testiamo per vedere se quel ROW è nullo. Questo funzionerà fino a quando ogni colonna IS NOT NULL. E, se ogni colonna IS NULLnella tua tabella, stai solo trollando.

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

La colonna b1utilizzata nella CASEsoluzione non deve essere non annullabile. La costruzione funziona in entrambi i casi.
ypercubeᵀᴹ

1

Trovo che COALESCE sia molto utile in quel caso. Restituirà il primo valore non NULL da un elenco:

SELECT
 a.a1,
 b.b1,
 COALESCE (b.b2, 100) AS b2
FROM a
LEFT OUTER JOIN b
  ON (a.a1 = b.b1);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.