Kann die Klausel 'returning' nicht eingefügte Quellenspalten zurückgeben?

14

Hier ist ein minimales Beispiel für mein reales Problem:

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

Natürlich können Sie die eingefügten Spalten mit einer returningKlausel zurückgeben:

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

Sie können auch ein Literal zurückgeben:

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 |
*/

Sie können die Quellspalten jedoch nicht zurückgeben:

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
*/

Gibt es eine Möglichkeit, w.rndaus der Schlussklausel herauszukommen returning?

db <> hier fummeln

Jack Douglas
quelle
In MS SQL Server können nur mit der MERGE-Anweisung zusätzliche Spalten zurückgegeben werden. Vielleicht funktioniert das auch für Postgres.
Sebastian Meine
Ich habe ein ähnliches Problem für UPDATEin dieser verwandten Antwort auf SO gelöst , aber das funktioniert nicht für INSERT.
Erwin Brandstetter

Antworten:

12

In der Dokumentation zu dieser RETURNINGKlausel heißt es:

Ein Ausdruck, der vom Befehl INSERT nach dem Einfügen jeder Zeile berechnet und zurückgegeben wird. Der Ausdruck kann beliebige Spaltennamen der Tabelle verwenden, die von table_name benannt werden. Schreiben Sie *, um alle Spalten der eingefügten Zeile (n) zurückzugeben.

Dies gilt eindeutig nicht für Spalten aus einer anderen Tabelle.

Obwohl ich den Grund des Problems nicht wirklich verstehe (z. B. warum Sie dies tun - ich stelle es mir vor, weil es eine etwas zu abstrakte Version des Originals ist), kann eine mögliche Lösung sein:

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;

Das heißt, Sie können mehr als einen beschreibbaren CTE an den Anfang einer Abfrage setzen. Bitte sehen Sie dies in Aktion an DBFiddle .

dezso
quelle