Czy klauzula „zwracająca” może zwracać kolumny źródłowe, które nie zostały wstawione?

14

Oto minimalny przykład mojego problemu w świecie rzeczywistym:

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

oczywiście możesz zwrócić wstawione kolumny z returningklauzulą:

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

możesz również zwrócić literał:

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

ale nie możesz zwrócić kolumn źródłowych:

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

Czy jest jakiś sposób na w.rndwyjście z ostatniej returningklauzuli?

db <> skrzypce tutaj

Jack mówi, że spróbuj topanswers.xyz
źródło
W MS SQL Server tylko instrukcja MERGE pozwala na zwrócenie dodatkowych kolumn. Może to też zadziała dla postgres.
Sebastian Meine,
Rozwiązałem podobny problem UPDATEw tej pokrewnej odpowiedzi dotyczącej SO , ale to nie zadziała INSERT.
Erwin Brandstetter

Odpowiedzi:

12

Dokumentacja RETURNINGklauzuli mówi:

Wyrażenie, które ma zostać obliczone i zwrócone przez polecenie INSERT po wstawieniu każdego wiersza. W wyrażeniu można użyć dowolnej nazwy kolumny tabeli o nazwie nazwa_tabeli. Napisz *, aby zwrócić wszystkie kolumny wstawionych wierszy.

To oczywiście nie dotyczy kolumn z innej tabeli.

Chociaż tak naprawdę nie rozumiem sedna problemu (tj. Dlaczego to robisz - wyobrażam sobie, że dzieje się tak, ponieważ jest to zbyt abstrakcyjna wersja oryginalnej), możliwe rozwiązanie to:

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;

Oznacza to, że na początku zapytania możesz umieścić więcej niż jeden zapis CTE. Zobacz to w akcji na dbfiddle .

dezso
źródło