La clause 'return' peut-elle renvoyer des colonnes source qui ne sont pas insérées?

14

Voici un exemple minimal de mon problème réel:

create table t(id serial primary key, rnd double precision);

bien sûr, vous pouvez renvoyer les colonnes insérées avec une returningclause:

with w as (insert into t(rnd) values(random()) returning *)
insert into t(rnd) select random() from w returning *;
/*
| ID |            RND |
|----|----------------|
|  9 | 0.203221440315 |
*/

vous pouvez également retourner un littéral:

with w as (insert into t(rnd) values(random()) returning *)
insert into t(rnd) select random() from w returning *, 1.0 dummy;
/*
| ID |            RND | DUMMY |
|----|----------------|-------|
| 11 | 0.594980469905 |     1 |
*/

mais vous ne pouvez pas renvoyer les colonnes source:

with w as (insert into t(rnd) values(random()) returning *)
insert into t(rnd) select random() from w returning *, w.rnd;
/*
ERROR: missing FROM-clause entry for table "w": with w as (insert into t(rnd) values(random()) returning *) insert into t(rnd) select random() from w returning *, w.rnd
*/

Existe-t-il un moyen de w.rndsortir de la returningclause finale ?

db <> violon ici

Jack dit d'essayer topanswers.xyz
la source
Dans MS SQL Server, seule l'instruction MERGE permet de renvoyer des colonnes supplémentaires. Peut-être que cela fonctionnera aussi pour les postgres.
Sebastian Meine
J'ai résolu un problème similaire UPDATEdans cette réponse connexe sur SO , mais cela ne fonctionnera pas INSERT.
Erwin Brandstetter

Réponses:

12

La documentation sur la RETURNINGclause dit:

Expression à calculer et à renvoyer par la commande INSERT après l'insertion de chaque ligne. L'expression peut utiliser n'importe quel nom de colonne de la table nommée par nom_table. Écrivez * pour renvoyer toutes les colonnes des lignes insérées.

Cela ne s'applique clairement pas aux colonnes d'une autre table.

Bien que je ne comprenne pas vraiment le problème (c'est-à-dire pourquoi vous faites cela - j'imagine que c'est parce que c'est une version un peu trop abstraite de l'original), une solution possible peut être:

WITH w AS (INSERT INTO t(rnd) VALUES (random()) RETURNING *),
     x AS (INSERT INTO t(rnd) SELECT random() FROM w RETURNING *)
SELECT w.rnd, x.rnd
  FROM w, x;

Autrement dit, vous pouvez placer plusieurs CTE inscriptibles au début d'une requête. Veuillez le voir en action sur dbfiddle .

dezso
la source