PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Les requêtes de type SELECT sont-elles le seul type pouvant être imbriqué ?

Réponse de base

Il existe des CTE (Expressions de table communes) dans Postgres (comme dans n'importe quel SGBDR moderne majeur à l'exception de MySQL). Depuis la version 9.1 qui inclut les CTE modifiant les données. Ceux-ci peuvent être "imbriqués".
Mise à jour :MySQL 8.0 ajoute enfin les CTE.

Contrairement aux sous-requêtes Les CTE constituent des barrières à l'optimisation. Le planificateur de requêtes ne peut pas intégrer de commandes triviales dans la commande principale ou réorganiser les jointures entre la requête principale et les CTE. La même chose est possible avec les sous-requêtes. Cela peut être (très) bon ou (très) mauvais pour les performances, cela dépend.
De toute façon, les CTE nécessitent un peu plus de surcharge (coût de performance) que les sous-requêtes.
Mise à jour :Postgres 12 peut enfin intégrer des CTE simples dans la requête principale.

Détails que vous n'avez pas demandés

Votre question est très basique, ce qui précède est probablement suffisant pour répondre. Mais je vais ajouter un peu pour les utilisateurs avancés (et un exemple de code pour montrer la syntaxe).

Tous les CTE d'une requête sont basés sur le même instantané de la base de données. Le prochain CTE peut réutiliser la sortie des CTE précédents (tables temporaires internes), mais les effets sur les tables sous-jacentes sont invisibles pour les autres CTE. La séquence de plusieurs CTE est arbitraire à moins que quelque chose est retourné avec le RETURNING clause pour INSERT , UPDATE , DELETE - non pertinent pour SELECT , puisqu'il ne change rien et lit simplement à partir de l'instantané.

Cela peut avoir des effets subtils avec plusieurs mises à jour qui affecteraient la même ligne. Seulement un la mise à jour peut affecter chaque ligne. Lequel est influencé par la séquence des CTE.

Essayez de prédire le résultat :

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;

Violon SQL

Ne soyez pas déçu, je doute qu'il y en ait beaucoup ici qui auraient pu le faire. :)
L'essentiel :éviter commandes en conflit dans les CTE.