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

Le query di tipo SELECT sono l'unico tipo che può essere nidificato?

Risposta di base

Ci sono CTE (Espressioni di tabelle comuni) in Postgres (come in tutti i principali RDBMS moderni tranne MySQL). Dalla versione 9.1 che include CTE di modifica dei dati. Questi possono essere "nidificati".
Aggiornamento:MySQL 8.0 aggiunge finalmente i CTE.

A differenza delle sottoquery I CTE rappresentano barriere di ottimizzazione. Il pianificatore di query non può incorporare comandi banali nel comando principale o riordinare i join tra query principale e CTE. Lo stesso è possibile con le sottoquery. Può essere (molto) buono o (molto) cattivo per le prestazioni, dipende.
In ogni caso, i CTE richiedono un po' più di sovraccarico (costo delle prestazioni) rispetto alle sottoquery.
Aggiornamento:Postgres 12 può finalmente inline CTE semplici nella query principale.

Dettagli non richiesti

La tua domanda è molto semplice, quanto sopra è probabilmente sufficiente per rispondere. Ma aggiungerò qualcosa per utenti avanzati (e un esempio di codice per mostrare la sintassi).

Tutti i CTE di una query si basano sullo stesso snapshot della banca dati. Il prossimo CTE può riutilizzare l'output dei CTE precedenti (tabelle temporanee interne), ma gli effetti sulle tabelle sottostanti sono invisibili per gli altri CTE. La sequenza di più CTE è arbitraria a meno che qualcosa viene restituito con RETURNING clausola per INSERT , UPDATE , DELETE - irrilevante per SELECT , poiché non cambia nulla e legge solo dall'istantanea.

Ciò può avere effetti sottili con più aggiornamenti che influirebbero sulla stessa riga. Solo uno l'aggiornamento può interessare ogni riga. Quale è influenzato dalla sequenza di CTE.

Prova a prevedere il risultato:

CREATE TEMP TABLE t (t_id int, txt text);
INSERT INTO t VALUES (1, 'foo'), (2, 'bar'), (3, 'baz');

WITH sel AS (SELECT * FROM t)
   , up1 AS (UPDATE t SET txt = txt || '1' WHERE t_id = 1 RETURNING *)
   , up2 AS (UPDATE t SET txt = t.txt || '2'
             FROM   up1
             WHERE  up1.t_id = t.t_id
             RETURNING t.*)
   , ins AS (INSERT INTO t VALUES (4, 'bamm'))
   , up3 AS (UPDATE t SET txt = txt || '3' RETURNING *)
SELECT 'sel' AS source, * FROM sel
UNION ALL
SELECT 'up1' AS source, * FROM up1
UNION ALL
SELECT 'up2' AS source, * FROM up2
UNION ALL
SELECT 'up3' AS source, * FROM up3
UNION ALL
SELECT 't'   AS source, * FROM t;

SQL Fiddle

Non essere deluso, dubito che ci siano molti qui che avrebbero potuto farlo. :)
Il succo di questo:evitare comandi in conflitto nelle CTE.