Imagine the following (fictional) situation:
You have a table with only one column id that is the primary key, autoincremented by using a typical sequence + trigger combination.
How would you create a new row there as you have to specify the values keyword for the insert query?
INSERT INTO table () VALUES () is not valid as far as I understood.
ATTENTION:
This is not a discussion about the sense of such a table! It is out of pure technical interest.
In any current Oracle version (12.1, 12.2, 18) I would not use a trigger but an identity column - then use the default keyword during insert:
create table x (id integer generated by default as identity);
insert into x (id) values (default);
How about
INSERT INTO theTable (id) VALUES (null);
and your before insert trigger would be like:
if :NEW.id is NULL Then
SELECT id_sequence.NEXTVAL INTO :NEW.id FROM dual;
end if;
Related
Basically, users when they create a new record in mytable1, there is an id field that needs to be the same across multiple tables. I achieve this by having mytable2 with the s_id as primary key
My current function looks like
CREATE OR REPLACE FUNCTION test.new_record()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
BEGIN
case when new.s_id in (select s_id from mytable1) then
insert into mytable2 (sprn, date_created) select max(s_id) +1, now() from mytable2 ;
update mytable1 set new.s_id = (select max(b.s_id) from mytable2 b);
end case;
RETURN new;
END;
$function$;
Intended was when the s_id is replicated then it would create a new entry on mytable2. This new entry would then be updated onto mytable1
Problem with this function is that right now it does not recognise the new on the update part of the function.
How to keep the s_id take the value on every new insert ?
If you want to have one "generator" across multiple tables, create one sequence that is used across all those tables for the default value:
create sequence the_id_sequence;
create table one
(
id integer primary key default nextval('the_id_sequence')
.... other columns
);
create table two
(
id integer primary key default nextval('the_id_sequence')
.... other columns ...
);
If you want to replicate an ID from one table to another during insert, you only need one sequence:
create table one
(
-- using identity is the preferred over "serial" to auto-generate PK values
id integer primary key generated always as identity
);
create table two
(
id integer primary key
);
create or replace function insert_two()
returns trigger
as
$$
begin
insert into two (id) values (new.id);
return new;
end;
$$
language plpgsql;
create trigger replicate_id
before insert on one
for each row
execute procedure insert_two();
Then if you run:
insert into one (id) values (default);
A row with exactly the same id value will be inserted into table two.
If you don't have a generated ID column so far, use the following syntax:
alter table one
add testidcolumn bigint generated always as identity;
Here's the scenario:
create table a (
id serial primary key,
val text
);
create table b (
id serial primary key,
a_id integer references a(id)
);
create rule a_inserted as on insert to a do also insert into b (a_id) values (new.id);
I'm trying to create a record in b referencing to a on insertion to a table. But what I get is that new.id is null, as it's automatically generated from a sequence. I also tried a trigger AFTER insert FOR EACH ROW, but result was the same. Any way to work this out?
To keep it simple, you could also just use a data-modifying CTE (and no trigger or rule):
WITH ins_a AS (
INSERT INTO a(val)
VALUES ('foo')
RETURNING a_id
)
INSERT INTO b(a_id)
SELECT a_id
FROM ins_a
RETURNING b.*; -- last line optional if you need the values in return
Related answer with more details:
PostgreSQL multi INSERT...RETURNING with multiple columns
Or you can work with currval() and lastval():
How to get the serial id just after inserting a row?
Reference value of serial column in another column during same INSERT
Avoid rules, as they'll come back to bite you.
Use an after trigger on table a that runs for each row. It should look something like this (untested):
create function a_ins() returns trigger as $$
begin
insert into b (a_id) values (new.id);
return null;
end;
$$ language plpgsql;
create trigger a_ins after insert on a
for each row execute procedure a_ins();
Don't use triggers or other database Kung fu. This situation happens every moment somewhere in the world - there is a simple solution:
After the insertion, use the LASTVAL() function, which returns the value of the last sequence that was auto-incremented.
Your code would look like:
insert into a (val) values ('foo');
insert into b (a_id, val) values (lastval(), 'bar');
Easy to read, maintain and understand.
I have a table that auto-increments its primary key. How can I return what this value currently is using SQL in HSQLDB?
I found this answer, but it doesn't give a full explanation of how to get it from a specific table.
If the primary key column is declared as IDENTITY, then I don't see a way to get the current value, except for calling the IDENTITY() as described in the other answer, which doesn't give the answer for the specific table.
An alternative is to create the primary key column to use a specific sequence generator instead of IDENTITY. You can then select the current value of the sequence from the INFORMATION_SCHEMA.SEQUENCE table.
The sample below shows how this would work.
create sequence test_seq;
create table test (
id integer generated by default as sequence test_seq,
value varchar(10));
insert into test (value) values ('foo');
insert into test (value) values ('bar');
insert into test (value) values ('bash');
select * from test;
id value
0 'foo'
1 'bar'
2 'bash'
select next_value from information_schema.sequences where sequence_name = 'TEST_SEQ'
3
For instance:
{create table Participant ( id serial, primary key(id) );}
How do you insert into table in this case?
If you create the table like above,
You can use default in following way to insert:
INSERT INTO Participant values(default);
Check out SQLFIDDLE.
Another way to insert is:
INSERT INTO Participant values(NEXTVAL('Participant_id_seq'));
CREATE TABLE will create implicit sequence "Participant_id_seq" for serial column "Participant.id".
You can get the sequence for the table using pg_get_serial_sequence function in following way:
pg_get_serial_sequence('Participant', 'id')
It will take new value from sequence using NEXTVAL().
Check out SQLFIDDLE
insert into Participant values (default);
I have a table and a procedure like this:
CREATE TABLE test_table (
id SERIAL PRIMARY KEY,
info TEXT);
create or replace function test() returns void as
$$
declare
v_row test_table%ROWTYPE;
begin
v_row.info := 'test';
insert into test_table values (v_row.*);
end;
$$ language plpgsql;
select test();
ERROR: null value in column "id" violates not-null constraint
How to use default value for the v_row.id field? I know I could write
insert into test_table (info) values (v_row.info);
But in my real case I have a lot of such tables with many columns and I really want to avoid enumerating all the columns in the insert statement.
By writing insert into test_table values (v_row.*); you actually force postgres to insert NULL value into the id column.
You will need to run such code - either in application
v_row.id := nextval( 'mysequence' );
.. or in trigger
IF NEW.id IS NULL THEN
NEW.id := nextval( 'mysequence' );
END IF;
You can check, if Postgresql have a SEQUENCE for this column and then, if this column have a DEFAULT value set. In psql try:
\d+ test_table
You have to see somethink like this:
id | integer | default nextval('test_table_id_seq'::regclass) |
If there is not a default nextval('somethink'), then you have to check, if there is sequnence for this column:
\ds+
You have to see somethink like this:
public | test_table_id_seq | sequence
If you will not have a sequence, you have a CREATE it:
CREATE SEQUENCE test_table_id_seq;
And if you will have not a `default nextval('somethink'), you have use a ALTER TABLE:
ALTER TABLE test_table ALTER COLUMN id SET DEFAULT nextval('test_table_id_seq');
You can find about it some informations here: http://www.postgresql.org/docs/8.1/static/datatype.html#DATATYPE-SERIAL
Perhaps you can understand it, although English is not my native language...