PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Qual è la differenza tra LATERAL JOIN e una sottoquery in PostgreSQL?

Che cosa è un LATERAL partecipare?

La funzionalità è stata introdotta con PostgreSQL 9.3. Il manuale:

Sottoquery che appaiono in FROM può essere preceduto dalla parola chiaveLATERAL . Ciò consente loro di fare riferimento alle colonne fornite da FROM precedente Oggetti. (Senza LATERAL , ogni sottoquery viene valutata in modo indipendente e quindi non può fare riferimento a nessun altro FROM elemento.)

Funzioni della tabella che appaiono in FROM può anche essere preceduto dalla parola chiave LATERAL , ma per le funzioni la parola chiave è facoltativa; gli argomenti della funzione possono contenere riferimenti a colonne fornite da FROM in ogni caso.

Qui vengono forniti esempi di codice di base.

Più simile a una correlata sottoquery

Un LATERAL join è più simile a una sottoquery correlata, non a una semplice sottoquery, in quanto espressioni a destra di un LATERAL join vengono valutati una volta per ogni riga rimasta, proprio come un correlato subquery - mentre una semplice sottoquery (espressione di tabella) viene valutata una volta solo. (Il pianificatore di query ha modi per ottimizzare le prestazioni per entrambi, tuttavia.)
Risposta correlata con esempi di codice per entrambi fianco a fianco, risolvendo lo stesso problema:

  • Ottimizza la query GROUP BY per recuperare l'ultima riga per utente

Per restituire più di una colonna , un LATERAL join è in genere più semplice, pulito e veloce.
Ricorda inoltre che l'equivalente di una sottoquery correlata è LEFT JOIN LATERAL ... ON true :

  • Richiama più volte una funzione di restituzione di set con un argomento array

Cose che una sottoquery non può fare

Ci ci sono cose che un LATERAL join può fare, ma una sottoquery (correlata) non può (facilmente). Una sottoquery correlata può restituire solo un singolo valore, non più colonne e non più righe, ad eccezione delle semplici chiamate di funzione (che moltiplicano le righe dei risultati se restituiscono più righe). Ma anche alcune funzioni di restituzione dei set sono consentite solo in FROM clausola. Come unnest() con più parametri in Postgres 9.4 o versioni successive. Il manuale:

Questo è consentito solo nel FROM clausola;

Quindi funziona, ma non può (facilmente) essere sostituito con una sottoquery:

CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2);  -- implicit LATERAL

La virgola (, ) nel FROM la clausola è una notazione breve per CROSS JOIN .
LATERAL viene assunto automaticamente per le funzioni di tabella.
Informazioni sul caso speciale di UNNEST( array_expression [, ... ] ) :

  • Come si fa a dichiarare che una funzione di ritorno dell'insieme è consentita solo nella clausola FROM?

Funzioni di ritorno degli insiemi nel SELECT elenco

Puoi anche utilizzare funzioni di restituzione di set come unnest() nel SELECT elencare direttamente. Questo mostrava un comportamento sorprendente con più di una di queste funzioni nello stesso SELECT elencare fino a Postgres 9.6. Ma finalmente è stato sanificato con Postgres 10 ed è ora una valida alternativa (anche se non SQL standard). Vedi:

  • Qual ​​è il comportamento previsto per più funzioni di restituzione di set nella clausola SELECT?

Basandosi sull'esempio sopra:

SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM   tbl;

Confronto:

dbfiddle per pg 9.6 qui
dbfiddle per pg 10 qui

Chiarire la disinformazione

Il manuale:

Per il INNER e OUTER tipi di join, è necessario specificare una condizione di join, ovvero esattamente una tra NATURAL , ON join_condition , o USING (join_column [, ...]). Vedi sotto per il significato.
Per CROSS JOIN , nessuna di queste clausole può comparire.

Quindi queste due query sono valide (anche se non particolarmente utili):

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;

SELECT *
FROM   tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Mentre questo non lo è:

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Ecco perché l'esempio di codice di Andomar è corretto (il CROSS JOIN non richiede una condizione di unione) e is di Attila non lo era.