You can find the sequence behind your serial column using pg_get_serial_sequence() and access it using currval() to get what serial column just got as a result of your INSERT.
CREATE TABLE mytable
( id SERIAL,
content TEXT,
copyofid INTEGER
);
--this works for a single-record insert
INSERT INTO mytable
(content, copyofid)
VALUES
('test', currval(pg_get_serial_sequence('mytable','id')));
--inserting more, you'll have to handle both columns relying on the sequence
INSERT INTO mytable
( id,
content,
copyofid)
VALUES
( nextval(pg_get_serial_sequence('mytable','id')),
'test3',
currval(pg_get_serial_sequence('mytable','id'))),
( nextval(pg_get_serial_sequence('mytable','id')),
'test4',
currval(pg_get_serial_sequence('mytable','id')));
table mytable;
-- id | content | copyofid
------+---------+----------
-- 1 | test | 1
-- 2 | test3 | 2
-- 3 | test4 | 3
--(3 rows)
Fiddle
Edouard makes makes a fair point that if you can specify the conditions when you want this behaviour, you can add them to the definition:
CREATE TABLE mytable
( id SERIAL,
content TEXT,
copyofid integer
generated always as (
case when content ilike '%requires copying ID%' then id end)
stored
);
insert into mytable (content) values ('abc') returning *;
-- id | content | copyofid
------+---------+----------
-- 1 | abc |
--(1 row)
insert into mytable (content) values ('abc, but requires copying ID') returning *;
-- id | content | copyofid
------+------------------------------+----------
-- 2 | abc, but requires copying ID | 2
--(1 row)
If they vary between inserts
CREATE TABLE mytable
( id SERIAL,
content TEXT,
copyofid integer
generated always as (
case when should_copy_id then id end)
stored,
should_copy_id boolean default false
);
insert into mytable (content) values ('efg') returning *;
-- id | content | copyofid | should_copy_id
------+---------+----------+----------------
-- 1 | efg | | f
--(1 row)
insert into mytable (content,should_copy_id) values ('klm','today'::date<>'2022-10-28'::date) returning *;
-- id | content | copyofid | should_copy_id
------+---------+----------+----------------
-- 2 | klm | 2 | t
--(1 row)
The trigger will be better if
- the check is fairly complex - generated columns are pretty limited in terms of the definition complexity. For example, you can't use mutable functions in them - not even
STABLE are accepted
- you want to save the logic and change it later without having to drop the column each time, then re-add it with a new definition (only way to alter a generated column definition)
- as a part of the
insert you'll want to do more than just copy the id column
generated column, see the manualmytableand which contains a test condition :IF condition THEN NEW.copyofid = NEW.id ; END IF ;