sql >> Database >  >> RDS >> PostgreSQL

Zijn query's van het SELECT-type het enige type dat kan worden genest?

Basisantwoord

Er zijn CTE's (Algemene tabeluitdrukkingen) in Postgres (zoals in elke grote moderne RDBMS behalve MySQL). Sinds versie 9.1 die CTE's voor het wijzigen van gegevens bevat. Die kunnen worden "genest".
Update:MySQL 8.0 voegt eindelijk CTE's toe.

In tegenstelling tot subquery's CTE's vormen een optimalisatiebarrière. De queryplanner kan geen triviale commando's in de hoofdcommando's opnemen of joins opnieuw ordenen tussen hoofdquery's en CTE's. Hetzelfde is mogelijk met subquery's. Kan (zeer) goed of (zeer) slecht zijn voor de prestaties, dat hangt ervan af.
Hoe dan ook, CTE's vereisen wat meer overhead (prestatiekosten) dan subquery's.
Update:Postgres 12 kan eindelijk gewone CTE's inline maken in de hoofdquery.

Details waar je niet om hebt gevraagd

Uw vraag is erg basic, het bovenstaande is waarschijnlijk voldoende om te beantwoorden. Maar ik zal een beetje toevoegen voor gevorderde gebruikers (en een codevoorbeeld om de syntaxis te tonen).

Alle CTE's van een zoekopdracht zijn gebaseerd op dezelfde momentopname van de databank. De volgende CTE kan de output opnieuw gebruiken van eerdere CTE's (interne tijdelijke tabellen), maar effecten op onderliggende tabellen zijn onzichtbaar voor andere CTE's. De volgorde van meerdere CTE's is willekeurig tenzij er wordt iets geretourneerd met de RETURNING clausule voor INSERT , UPDATE , DELETE - niet relevant voor SELECT , omdat het niets verandert en gewoon leest van de momentopname.

Dat kan subtiele effecten hebben met meerdere updates die dezelfde rij zouden beïnvloeden. Slechts één update kan elke rij beïnvloeden. Welke wordt beïnvloed door de volgorde van CTE's.

Probeer de uitkomst te voorspellen:

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

Wees niet teleurgesteld, ik betwijfel of er hier velen zijn die het hadden kunnen doen. :)
De kern hiervan:vermijd tegenstrijdige opdrachten in CTE's.




  1. MySQL onjuiste tekenreekswaardefout bij het opslaan van unicode-tekenreeks in Django

  2. Hoe de RLIKE-operator werkt in MySQL

  3. Waarom krijg ik Kan parameter 2 niet doorgeven door een verwijzingsfout wanneer ik bindParam gebruik met een constante waarde?

  4. CURRENT_TIMESTAMP Voorbeelden – MySQL