Bisakah 'kembali' klausa kolom kembali sumber yang tidak dimasukkan?

14

Inilah contoh minimal masalah dunia nyata saya:

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

tentu saja Anda dapat mengembalikan kolom yang disisipkan dengan returningklausa:

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

Anda juga dapat mengembalikan literal:

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

tetapi Anda tidak dapat mengembalikan kolom sumber:

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

Apakah ada cara saya bisa w.rndkeluar dari returningklausa terakhir ?

db <> biola di sini

Jack mengatakan coba topanswers.xyz
sumber
Dalam MS SQL Server hanya pernyataan MERGE yang memungkinkan kolom tambahan untuk dikembalikan. Mungkin itu akan berhasil untuk postgres juga.
Sebastian Meine
Saya memecahkan masalah yang sama UPDATEdalam jawaban terkait ini pada SO , tetapi ini tidak akan berhasil INSERT.
Erwin Brandstetter

Jawaban:

12

Dokumentasi pada RETURNINGklausa mengatakan:

Ekspresi yang akan dihitung dan dikembalikan oleh perintah INSERT setelah setiap baris dimasukkan. Ekspresi dapat menggunakan nama kolom dari tabel yang dinamai dengan table_name. Tulis * untuk mengembalikan semua kolom dari baris yang dimasukkan.

Ini jelas tidak berlaku untuk kolom dari tabel lain.

Meskipun saya tidak benar-benar mengerti masalahnya (yaitu mengapa Anda melakukan ini - saya bayangkan itu karena versi yang agak terlalu abstrak dari yang asli), solusi yang mungkin adalah:

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;

Artinya, Anda dapat menempatkan lebih dari satu CTE yang dapat ditulis ke awal kueri. Silakan lihat ini beraksi di dbfiddle .

dezso
sumber