sql >> Databáze >  >> RDS >> PostgreSQL

Jsou dotazy typu SELECT jediným typem, který lze vnořit?

Základní odpověď

Existují CTE (Common Table Expressions) v Postgres (jako v každém velkém moderním RDBMS kromě MySQL). Od verze 9.1, která zahrnuje CTE upravující data. Ty lze „vnořit“.
Aktualizace:MySQL 8.0 konečně přidává CTE.

Na rozdíl od poddotazů CTE představují optimalizační bariéry. Plánovač dotazů nemůže vkládat triviální příkazy do hlavního příkazu nebo měnit pořadí spojení mezi hlavním dotazem a CTE. Totéž je možné s poddotazy. Může být (velmi) dobrý nebo (velmi) špatný z hlediska výkonu, to záleží.
V každém případě vyžadují CTE o něco větší režii (náklady na výkon) než dílčí dotazy.
Aktualizace:Postgres 12 může konečně vkládat prosté CTE v hlavním dotazu.

Podrobnosti, na které jste se neptali

Vaše otázka je velmi základní, výše uvedené pravděpodobně stačí k zodpovězení. Ale přidám trochu pro pokročilé uživatele (a příklad kódu pro ukázku syntaxe).

Všechny CTE dotazu jsou založeny na stejném snímku databáze. Další CTE může znovu použít výstup předchozích CTE (interní dočasné tabulky), ale účinky na podkladové tabulky jsou pro ostatní CTE neviditelné. Posloupnost více CTE je libovolná pokud něco je vráceno pomocí RETURNING klauzule pro INSERT , UPDATE , DELETE - irelevantní pro SELECT , protože nic nemění a pouze čte ze snímku.

To může mít jemné efekty s více aktualizacemi, které by ovlivnily stejný řádek. Pouze jeden aktualizace může ovlivnit každý řádek. Který z nich je ovlivněn posloupností CTE.

Zkuste předpovědět výsledek:

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

Nebuďte zklamaní, pochybuji, že je tu mnoho těch, kteří to dokázali. :)
Podstata toho:vyhnout se konfliktní příkazy v CTE.




  1. Problém s vytvořením cizího klíče v Oracle

  2. Řazení hodnot null po všech ostatních, kromě speciálních

  3. Cheat Sheet pro Access 2021 For Dummies

  4. Dotaz k prohledání všech balíčků na tabulku a/nebo sloupec