Here we have a certain table:
CREATE TABLE mytbl (
id int PRIMARY KEY generated by default as identity,
col1 int,
col2 text, ...
);
We need to copy part of the rows of the table and get information about the correspondence of the old and new IDs (in order to then copy the related data from other tables).
I tried such a query:
insert into mytbl (col1, col2)
select col1, col2
from mytbl old
where col1 = 999 -- some condition
returning
old.id as old_id,
id as new_id;
But this query produces the error:
ERROR: missing FROM-clause entry for table "old"
Is there a way to write a similar query without an error?
What I've already thought about:
- copy one line at a time in a loop — apparently I will have to, unless an easier way is found.
alter table mytbl add column old_id(foreign key references mytbl) and theninsert into mytbl (old_id, col1, col2) select id, col1, col2 ... returning id as new_id, old_id— but in reality, we do not need to store this information, because it is needed only at the moment of creating a copy.- INSERT SELECT without RETURNING; and then
SELECT old.id as old_id, new.id as new_id FROM mytbl new JOIN mytbl old ON(some connection condition by intelligent key) — is quite difficult in my case.
You can (but probably shouldn't) rely on the order of inserted rows to match between the selection and the
RETURNINGclause:A probably better approach (which also works nicely when you need to copy in multiple mutually-dependant tables) is to generate the new ids ahead of the insert, using the sequence that is underlying the identity column:
This does however require
USAGEpermission on the underlying sequence, which may not be granted by default even if a role can normally use the identity column.