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;
id | name | id | header_id | name |
---|---|---|---|---|
1 | header_one | 1 | 1 | value 1 |
1 | header_one | 2 | 1 | value 2 |
1 | header_one | 3 | 1 | value 3 |
2 | header_two | 4 | 2 | value 1 |
2 | header_two | 5 | 2 | value 2 |
2 | header_two | 6 | 2 | value 3 |
3 | header_one | 7 | 3 | value 1 |
3 | header_one | 8 | 3 | value 2 |
3 | header_one | 9 | 3 | value 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
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