How to to get the value of an auto increment column in postgres from a .sql script file? - sql

In postgres I have two tables like so
CREATE TABLE foo (
pkey SERIAL PRIMARY KEY,
name TEXT
);
CREATE TABLE bar (
pkey SERIAL PRIMARY KEY,
foo_fk INTEGER REFERENCES foo(pkey) NOT NULL,
other TEXT
);
What I want to do is to write a .sql script file that does the following
INSERT INTO foo(name) VALUES ('A') RETURNING pkey AS abc;
INSERT INTO bar(foo_fk,other) VALUES
(abc, 'other1'),
(abc, 'other2'),
(abc, 'other3');
which produces the error below in pgAdmin
Query result with 1 row discarded.
ERROR: column "abc" does not exist
LINE 3: (abc, 'other1'),
********** Error **********
ERROR: column "abc" does not exist
SQL state: 42703
Character: 122
Outside of a stored procedure how do a define a variable that I can use between statements? Is there some other syntax for being able to insert into bar with the pkey returned from the insert to foo.

You can combine the queries into one. Something like:
with foo_ins as (INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey AS foo_id)
INSERT INTO bar(foo_fk,other)
SELECT foo_id, 'other1' FROM foo_ins
UNION ALL
SELECT foo_id, 'other2' FROM foo_ins
UNION ALL
SELECT foo_id, 'other3' FROM foo_ins;
Other option - use an anonymous PL/pgSQL block like:
DO $$
DECLARE foo_id INTEGER;
BEGIN
INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey INTO foo_id;
INSERT INTO bar(foo_fk,other)
VALUES (foo_id, 'other1'),
(foo_id, 'other2'),
(foo_id, 'other3');
END$$;

You can use lastval() to ...
Return the value most recently returned by nextval in the current session.
This way you do not need to know the name of the seqence used.
INSERT INTO foo(name) VALUES ('A');
INSERT INTO bar(foo_fk,other) VALUES
(lastval(), 'other1')
, (lastval(), 'other2')
, (lastval(), 'other3')
;
This is safe because you control what you called last in your own session.
If you use a writable CTE as proposed by #Ihor, you can still use a short VALUES expression in the 2nd INSERT. Combine it with a CROSS JOIN (or append the CTE name after a comma (, ins) - same thing):
WITH ins AS (
INSERT INTO foo(name)
VALUES ('A')
RETURNING pkey
)
INSERT INTO bar(foo_fk, other)
SELECT ins.pkey, o.other
FROM (
VALUES
('other1'::text)
, ('other2')
, ('other3')
) o(other)
CROSS JOIN ins;

Another option is to use currval
INSERT INTO foo
(name)
VALUES
('A') ;
INSERT INTO bar
(foo_fk,other)
VALUES
(currval('foo_pkey_seq'), 'other1'),
(currval('foo_pkey_seq'), 'other2'),
(currval('foo_pkey_seq'), 'other3');
The automatically created sequence for serial columns is always named <table>_<column>_seq
Edit:
A more "robust" alternative is to use pg_get_serial_sequence as Igor pointed out.
INSERT INTO bar
(foo_fk,other)
VALUES
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other1'),
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other2'),
(currval(pg_get_serial_sequence('public.foo', 'pkey')), 'other3');

Related

INSERT row in table a for every row in table b [duplicate]

If I have an SQL table with all default columns (e.g. identity column + any number of columns all with default values), what is the SQL statement to insert a row with no explicit values given?
insert MyTable /* ( doh, no fields! ) */
-- values( doh, no values! )
What's the trick?
This is a part of the INSERT syntax
INSERT INTO TableName DEFAULT VALUES
Read more here:
https://learn.microsoft.com/en-us/sql/t-sql/statements/insert-transact-sql
You can use the DEFAULT keyword.
The accepted answer only works for one row, not for multiple rows.
Let us assume you know how many rows to insert, but you want all default values. You cannot do the following, for instance
INSERT MyTable
SELECT DEFAULT VALUES -- Incorrect syntax near the keyword 'DEFAULT'.
FROM SomeQueryOrView;
-- or
INSERT MyTable
DEFAULT VALUES -- Incorrect syntax near the keyword 'FROM'.
FROM SomeQueryOrView;
Instead we can hack MERGE to do this
MERGE INTO myTable
USING (SELECT SomeValue FROM SomeQueryOrView) s
ON 1 = 0 -- never match
WHEN NOT MATCHED THEN
INSERT DEFAULT VALUES;
A bonus benefit is that we can OUTPUT data from columns which are not being inserted:
MERGE INTO myTable
USING (SELECT SomeValue FROM SomeQueryOrView) s
ON 1 = 0 -- never match
WHEN NOT MATCHED THEN
INSERT DEFAULT VALUES
OUTPUT inserted.Id, s.SomeValue;

Use a returning value from an INSERT table (A) into another table (B)

I need to use the returning value of the Table A (ID) and insert it in Table B as a parameter:
insert into tableA (ID, Name , Address)
values (GEN_ID(GENERATOR,1),'John','123 street')
returning ID
--Example: ID=159
insert into tableB (ID, TABLE_A_FK )
values (GEN_ID(GENERATOR,1), 159)
Instead of entering the actual value 159, can I create like a variable (e.g. declare ID int;), and just pass the parameter?
The only way to do this in a single statement, is to use EXECUTE BLOCK (basically an anonymous one-off procedure). It uses the same syntax as normal stored procedures in Firebird.
You can do:
execute block
as
declare id integer;
begin
insert into tableA (ID, Name , Address)
values (GEN_ID(GENERATOR,1), 'John', '123 street')
returning ID
into id;
insert into tableB (ID, TABLE_A_FK)
values (GEN_ID(GENERATOR,1), :id);
end
If necessary, execute block statements can be parameterized, so you can use parameters to provide values (instead of hard coding them). See the link above for details.

SQLDelight FTS5 insert trouble

I created a table in DBBrowser:
CREATE VIRTUAL TABLE IF NOT EXISTS Students USING FTS5
(
GroupId UNINDEXED,
StudentName
);
and insert values to it. After that I add DB with this table to my project.
It is declaration of this table in sqldelight .sq file:
CREATE VIRTUAL TABLE IF NOT EXISTS Students USING FTS5
(
GroupId INTEGER AS Int,
StudentName TEXT,
rank REAL
);
I need to explicit declare rank because I want to apply HAVING MIN(rank) for it when SELECT from table (otherwise it is not compile), but when I trying to insert values in table like that:
insert:
INSERT INTO Students VALUES (?,?);
I receive an error:
Unexpected number of values being inserted. found: 2 expected: 3
If I do like that:
insert:
INSERT INTO Students VALUES (?,?,?);
I receive an exception:
SQLiteException - table Students has 2 columns but 3 values were supplied (code 1): , while compiling: INSERT INTO Students VALUES (?,?,?)
How I can perform insert? Or maybe I can apply HAVING MIN(rank) without explicit declare?
does
insert:
INSERT INTO Students(GroupId, StudentName) VALUES (?,?);
work?

Create custom defined unique identifier

I have a table with uniqueidentifier column. Insert script looks like this :
INSERT INTO [Users] ([UserId], [Name], [Surname]) VALUES (NEWID(), 'SomeName', 'SomeSurname')
NEWID() creates new GUID, which is inserted to table. I would like to create some data with defined id column, not automatically generated. E.g. 'a0000000-0000-0000-0000-000000000000'. This code doesn't work because it throws error 'String or binary data would be truncated.' :
INSERT INTO [Users] ([UserId], [Name], [Surname]) VALUES ('a0000000-0000-0000-0000-000000000000', 'SomeName', 'SomeSurname')
I tried cast this custom guid, but I was not successful as well.
INSERT INTO [Users] ([UserId], [Name], [Surname]) VALUES (CAST('a0000000-0000-0000-0000-000000000000' AS uniqueidentifier), 'SomeName', 'SomeSurname')
Do you have any clue how I can solve inserting data with custom defined ID?
You don't have to cast it. SQL Server will do it for you.
This code works well:
create table x
( a uniqueidentifier
);
insert into x values ('A0000000-0000-0000-0000-000000000000')
;
insert into x values ('BBE46A77-3518-40E4-9B77-3275F3531B8B')
;
select *
from x
;

can't insert data into table

I have created table using this command successfully
create table Person(
first_name varchar(25) not null,
last_name varchar(25) not null,
persoin_id number not null,
birth_date date,
country varchar (25),
salary number);
and now I want to insert data into that table
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
values(100,'dato','datuashvili',350,to_date('01/01/10','DD/MM/YY'),'georgia');
values(101,'irakli','oqruashvili',350,to_date('01/03/10','DD/MM/YY'),'georgia');
first row is inserted,but problem is with second line
1 rows inserted.
Error starting at line 10 in command:
values(101,'irakli','oqruashvili',350,to_date('01/03/10','DD/MM/YY'),'georgia')
Error report:
Unknown Command
Please help me to determine what is problem?thanks
If you are on a RDBMS that supports multi-rows inserts in one INSERT:
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
values
(100,'dato','datuashvili',350,to_date('01/01/10','DD/MM/YY'),'georgia') ,
--- comma here ---^
(101,'irakli','oqruashvili',350,to_date('01/03/10','DD/MM/YY'),'georgia') ;
^--- no "values" here
If not (like Oracle), you'll have to issue two insert statements:
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
values
(100,'dato','datuashvili',350,to_date('01/01/10','DD/MM/YY'),'georgia') ;
--- as it was here ---^
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
values
(101,'irakli','oqruashvili',350,to_date('01/03/10','DD/MM/YY'),'georgia') ;
or use this approach:
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
select
(100,'dato','datuashvili',350,to_date('01/01/10','DD/MM/YY'),'georgia')
from dual
union all select
(101,'irakli','oqruashvili',350,to_date('01/03/10','DD/MM/YY'),'georgia')
from dual
;
You will need to use 2 insert statement instead of one for 2 different sets of data...
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
values(100,'dato','datuashvili',350,to_date('01/01/10','DD/MM/YY'),'georgia');
insert into Person(persoin_id,first_name,last_name,salary,birth_date,country)
values(101,'irakli','oqruashvili',350,to_date('01/03/10','DD/MM/YY'),'georgia')
You have a ; at the end of:
values(100,'dato','datuashvili',350,to_date('01/01/10','DD/MM/YY'),'georgia');
^
change it to , and also loose the values from the next line. You need just one values per insert.