A cláusula 'return' pode retornar colunas de origem que não foram inseridas?

14

Aqui está um exemplo mínimo do meu problema do mundo real:

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

é claro que você pode retornar as colunas inseridas com uma returningcláusula:

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

você também pode retornar um 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 |
*/

mas você não pode retornar as colunas de origem:

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 alguma maneira de w.rndsair da returningcláusula final ?

db <> mexer aqui

Jack diz que tenta topanswers.xyz
fonte
No MS SQL Server, apenas a instrução MERGE permite que colunas adicionais sejam retornadas. Talvez isso funcione também para o postgres.
Sebastian Meine 28/09
Resolvi um problema semelhante UPDATEnesta resposta relacionada ao SO , mas isso não funcionará INSERT.
Erwin Brandstetter

Respostas:

12

A documentação da RETURNINGcláusula diz:

Uma expressão a ser calculada e retornada pelo comando INSERT após a inserção de cada linha. A expressão pode usar qualquer nome de coluna da tabela nomeada por table_name. Escreva * para retornar todas as colunas da (s) linha (s) inserida (s).

Isso claramente não se aplica a colunas de outra tabela.

Embora eu realmente não entenda o problema (ou seja, por que você faz isso - eu imagino que seja porque é uma versão um pouco abstrata demais da original), uma solução possível pode ser:

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;

Ou seja, você pode colocar mais de um CTE gravável no início de uma consulta. Por favor, veja isso em ação no dbfiddle .

dezso
fonte