Может ли предложение return возвращать исходные столбцы, которые не вставлены?

14

Вот минимальный пример моей реальной проблемы:

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

Конечно, вы можете вернуть вставленные столбцы с returningпредложением:

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

Вы также можете вернуть литерал:

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

но вы не можете вернуть исходные столбцы:

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

Есть ли какой-нибудь способ, которым я могу выйти w.rndиз последнего returningпункта?

дБ <> скрипка здесь

Джек говорит, попробуйте topanswers.xyz
источник
В MS SQL Server только оператор MERGE допускает возврат дополнительных столбцов. Может быть, это будет работать и для Postgres.
Себастьян Майн,
Я решил аналогичную проблему UPDATEв этом связанном ответе на SO , но это не сработает INSERT.
Эрвин Брандштеттер

Ответы:

12

Документация по RETURNINGпункту гласит:

Выражение, которое будет вычислено и возвращено командой INSERT после вставки каждой строки. Выражение может использовать любые имена столбцов таблицы с именем table_name. Напишите *, чтобы вернуть все столбцы вставленных строк.

Это явно не относится к столбцам из другой таблицы.

Хотя я не совсем понимаю суть проблемы (то есть, почему вы это делаете - я думаю, это потому, что это слишком абстрактная версия оригинала), возможное решение может быть:

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;

То есть вы можете поместить более одного доступного для записи CTE в начало запроса. Пожалуйста, посмотрите это в действии на dbfiddle .

Dezso
источник