Re: [SQL] Unable to use INSERT ... RETURNING with column fromother table - Mailing list pgsql-sql

From Andreas Joseph Krogh
Subject Re: [SQL] Unable to use INSERT ... RETURNING with column fromother table
Date
Msg-id VisenaEmail.5f.363e3023a414a542.15f50dcaa73@tc7-visena
Whole thread Raw
In response to Re: [SQL] Unable to use INSERT ... RETURNING with column fromother table  (Andreas Joseph Krogh <andreas@visena.com>)
Responses Re: [SQL] Unable to use INSERT ... RETURNING with column from other table
List pgsql-sql
På onsdag 25. oktober 2017 kl. 00:49:05, skrev Andreas Joseph Krogh <andreas@visena.com>:
På onsdag 25. oktober 2017 kl. 00:06:59, skrev Peter Geoghegan <pg@bowt.ie>:
On Tue, Oct 24, 2017 at 3:04 PM, Andreas Joseph Krogh
<andreas@visena.com> wrote:
> insert into foo(id, name) values(1, 'one'), (2, 'two');
>
> insert into foo(id, name) select 3, f.name from foo f where f.id = 1 returning id, f.id;
>
> ERROR:  missing FROM-clause entry for table "f"
> LINE 1: ...lect 3, f.name from foo f where f.id = 1 returning id, f.id;
>
> I'd like to return f.id and the inserted id, is this possible?

It's possible on 9.5+. You need to assign the target table an alias
using AS -- AS in not a noise word for INSERT (the grammar requires
it).

See the INSERT documentation.
 
I'm not sure how an alias for the target_table will help me here as I'm trying to return a value not being inserted?
f.id is not inserted, only columns matching f.id.
 
 
 
What I want to accomplish is returning a value from INSERT which is part of the SELECT-expression's FROM-clause, not part of the actual inserted columns:
 
My real-world use-case isn't quite this simple but this sample-case illustrates the problem;
 
DROP TABLE IF EXISTS tbl_value;
DROP TABLE IF EXISTS tbl_header;

CREATE TABLE tbl_header(   id INTEGER PRIMARY KEY,   name VARCHAR NOT NULL
);

CREATE TABLE tbl_value(   id SERIAL PRIMARY KEY,   header_id INTEGER NOT NULL REFERENCES tbl_header(id),   name VARCHAR NOT NULL
);

INSERT INTO tbl_header(id, name) VALUES(1, 'header_one'), (2, 'header_two');

INSERT INTO tbl_value(id, header_id, name)
VALUES(1, 1, 'value 1'),(2, 1, 'value 2'),(3, 1, 'value 3')   , (4, 2, 'value 1'),(5, 2, 'value 2'),(6, 2, 'value 3');

SELECT setval('tbl_value_id_seq', 6);

WITH upd_h(new_header_id, header_name, old_header_id) AS (   INSERT INTO tbl_header(id, name)       SELECT 3, h.name       FROM tbl_header h WHERE h.id = 1
    RETURNING id, name, 1 -- need h.id here
)   INSERT INTO tbl_value(header_id, name)
SELECT f.new_header_id, hv.name
FROM tbl_value hv   JOIN tbl_header h ON hv.header_id = h.id   JOIN upd_h AS f ON hv.header_id = f.old_header_id
;

select h.*, v.* from tbl_header h JOIN tbl_value v ON v.header_id = h.id ORDER BY h.id, v.id;
 
idnameidheader_idname
1header_one11value 1
1header_one21value 2
1header_one31value 3
2header_two42value 1
2header_two52value 2
2header_two62value 3
3header_one73value 1
3header_one83value 2
3header_one93value 3
 
 
 
I need to return the value for h.id in the first INSERT:
 
WITH upd_h(new_header_id, header_name, old_header_id) AS (   INSERT INTO tbl_header(id, name)       SELECT 3, h.name       FROM tbl_header h WHERE h.id = 1
    RETURNING id, name, h.id
)   INSERT INTO tbl_value(header_id, name)
SELECT f.new_header_id, hv.name
FROM tbl_value hv   JOIN tbl_header h ON hv.header_id = h.id   JOIN upd_h AS f ON hv.header_id = f.old_header_id
;
 
This fails with:
ERROR:  missing FROM-clause entry for table "h"
LINE 5:     RETURNING id, name, h.id


 
Is what I'm trying to do possible? I'd like to avoid having to use temp-tables and/or PLPgSQL for this as I need to insert many such values in large batches...
 
Thanks.
 
--
Andreas Joseph Krogh
CTO / Partner - Visena AS
Mobile: +47 909 56 963
 

pgsql-sql by date:

Previous
From: Andreas Joseph Krogh
Date:
Subject: Re: [SQL] Unable to use INSERT ... RETURNING with column fromother table
Next
From: "David G. Johnston"
Date:
Subject: Re: [SQL] Unable to use INSERT ... RETURNING with column from other table