Get identity column values upon INSERT - sql

I am using SQL Server 2008 to create a procedure.
I am using the following sql statement to insert into a audit table
insert into Listuser
(
UserID,
ListID,
AuditCreated
)
select
UserID,
ListID,
GETDATE()
from ListUser where Surname='surname'
I am using scope_identity() to get the identity column from the listuser table and insert the identity column to another logs table
If the select statement contains more than 1 value, how to get the identity value of both columns and insert into logs table?
Thanjs

If you need to capture multiple identity values being inserted, I'd use the OUTPUT clause:
DECLARE #TableOfIdentities TABLE (IdentValue INT)
INSERT INTO dbo.Listuser(UserID, ListID, AuditCreated)
OUTPUT Inserted.ID INTO #TableOfIdentities(IdentValue)
SELECT
UserID, ListID, GETDATE()
FROM
dbo.ListUser
WHERE
Surname = 'surname'
This will insert all rows into your ListUser table, and it will output all identities generated by this INSERT into the #TableOfIdentities table variable
Read more about the OUTPUT clause on MSDN
These values are inserted into the table variable, and you can select them out from that table variable after the insert, and do whatever you need to do with them:
SELECT * FROM #TableOfIdentities
Update: the use of the table variable here is just as an example - of course you can also output the data into a "normal" table in SQL Server - and you can also output multiple values for each inserted row, if you need that - so you can have something like:
INSERT INTO dbo.Listuser(UserID, ListID, AuditCreated)
OUTPUT Inserted.ID, Inserted.UserID, Inserted.SurName, GETDATE()
INTO AuditTable(IdentValue, UserID, Surname, InsertDate)
SELECT
UserID, ListID, GETDATE()
FROM
dbo.ListUser
WHERE
Surname = 'surname'

Related

Insert into table from select only when select returns valid rows

I want to insert into table from select statement but it is required that insert only happens when select returns valid rows. If no rows return from select, then no insertion happens.
insert into products (name, type) select 'product_name', type from prototype where id = 1
However, the above sql does insertion even when select returns no rows.
It tries to insert NULL values.
I know the following sql can check if row exists
select exists (select true from prototype where id = 1)
How to write a single SQL to add the above condition to insert to exclude the case ?
You are inserting the wrong way. See the example below, that doesn't insert any row since none matches id = 1:
create table products (
name varchar(10),
type varchar(10)
);
create table prototype (
id int,
name varchar(10),
type varchar(10)
);
insert into prototype (id, name, type) values (5, 'product5', 'type5');
insert into prototype (id, name, type) values (7, 'product7', 'type7');
insert into products (name, type) select name, type from prototype where id = 1
-- no rows were inserted.

How to Lock multiple tables for Insert command in Sql

This is my table Structure
When I insert Data into the first table, it will have multiple entries in table 2
I am Using code
To Get ID
Select MAX(ID)+1 From Table1
To Insert Data
Insert Into Table1 Values('1','abc','add1');
Insert into table2 values('1','med','english');
Insert into table2 values('1','eng','english');
Code is working fine for single computer but when we used in application in multiple terminals it is inserting wrong data i.e. data of another id in table2
You need ensure that the ID column of table1 is an identity column and then do the following:
DECLARE #ID INT
INSERT table1 ([columns])
VALUES (...)
SELECT #ID = SCOPE_IDENTITY()
INSERT table2 (table1ID, [columns])
VALUES (#ID, ...)
You can read more about SCOPE_IDENTITY() here.
MAX(ID) will include ID values created by other processes, which is why your second insert is mixing up data.

Insert New data into multiple tables with Foreign Key simultaneously in One query in sql server

I have two tables:
tblDepartment:
Id Name
and
tblEmployee:
Id FullName Dept_ID
Dept_ID is a foreign key for tblDepartment
I want to insert a new record into both tables.
I tried this:
declare #id int
insert dbo.tblDepartment
select Name='Name1'
select id = scope_Identity()
insert dbo.tblEmployee
select FullName = 'Name1'
select Dept_Id=#id
select Id=#id
However, this is not working. I searched through other posts, but they contain solutions for inserting existing data from one table into another, not creating a new record. How can I do this in one query?
You need to use variables properly along with column lists for inserts. Assuming you are using SQL Server:
declare #id int ;
insert dbo.tblDepartment(Name)
select 'Name1';
select #id = scope_Identity();
insert dbo.tblEmployee(FullName, Dept_Id)
select 'Name1', #id;
Also, scope_identity() is okay for learning about such id's. The safe way to really get this information is to use the output clause.
declare #id int
insert dbo.tblDepartment(Name)
select 'Name1'
-- Don't insert any other statements before next line...
select #id=scope_Identity()
insert dbo.tblEmployee(Fullname, Dept_ID)
select 'Name1', #id

Insert data in 3 tables at a time using Postgres

I want to insert data into 3 tables with a single query.
My tables looks like below:
CREATE TABLE sample (
id bigserial PRIMARY KEY,
lastname varchar(20),
firstname varchar(20)
);
CREATE TABLE sample1(
user_id bigserial PRIMARY KEY,
sample_id bigint REFERENCES sample,
adddetails varchar(20)
);
CREATE TABLE sample2(
id bigserial PRIMARY KEY,
user_id bigint REFERENCES sample1,
value varchar(10)
);
I will get a key in return for every insertion and I need to insert that key in the next table.
My query is:
insert into sample(firstname,lastname) values('fai55','shaggk') RETURNING id;
insert into sample1(sample_id, adddetails) values($id,'ss') RETURNING user_id;
insert into sample2(user_id, value) values($id,'ss') RETURNING id;
But if I run single queries they just return values to me and I cannot reuse them in the next query immediately.
How to achieve this?
Use data-modifying CTEs:
WITH ins1 AS (
INSERT INTO sample(firstname, lastname)
VALUES ('fai55', 'shaggk')
-- ON CONFLICT DO NOTHING -- optional addition in Postgres 9.5+
RETURNING id AS sample_id
)
, ins2 AS (
INSERT INTO sample1 (sample_id, adddetails)
SELECT sample_id, 'ss' FROM ins1
RETURNING user_id
)
INSERT INTO sample2 (user_id, value)
SELECT user_id, 'ss2' FROM ins2;
Each INSERT depends on the one before. SELECT instead of VALUES makes sure nothing is inserted in subsidiary tables if no row is returned from a previous INSERT. (Since Postgres 9.5+ you might add an ON CONFLICT.)
It's also a bit shorter and faster this way.
Typically, it's more convenient to provide complete data rows in one place:
WITH data(firstname, lastname, adddetails, value) AS (
VALUES -- provide data here
('fai55', 'shaggk', 'ss', 'ss2') -- see below
, ('fai56', 'XXaggk', 'xx', 'xx2') -- works for multiple input rows
-- more?
)
, ins1 AS (
INSERT INTO sample (firstname, lastname)
SELECT firstname, lastname -- DISTINCT? see below
FROM data
-- ON CONFLICT DO NOTHING -- UNIQUE constraint? see below
RETURNING firstname, lastname, id AS sample_id
)
, ins2 AS (
INSERT INTO sample1 (sample_id, adddetails)
SELECT ins1.sample_id, d.adddetails
FROM data d
JOIN ins1 USING (firstname, lastname)
RETURNING sample_id, user_id
)
INSERT INTO sample2 (user_id, value)
SELECT ins2.user_id, d.value
FROM data d
JOIN ins1 USING (firstname, lastname)
JOIN ins2 USING (sample_id);
db<>fiddle here
You may need explicit type casts in a stand-alone VALUES expression - as opposed to a VALUES expression attached to an INSERT where data types are derived from the target table. See:
Casting NULL type when updating multiple rows
If multiple rows can come with identical (firstname, lastname), you may need to fold duplicates for the first INSERT:
...
INSERT INTO sample (firstname, lastname)
SELECT DISTINCT firstname, lastname FROM data
...
You could use a (temporary) table as data source instead of the CTE data.
It would probably make sense to combine this with a UNIQUE constraint on (firstname, lastname) in the table and an ON CONFLICT clause in the query.
Related:
How to use RETURNING with ON CONFLICT in PostgreSQL?
Is SELECT or INSERT in a function prone to race conditions?
Something like this
with first_insert as (
insert into sample(firstname,lastname)
values('fai55','shaggk')
RETURNING id
),
second_insert as (
insert into sample1( id ,adddetails)
values
( (select id from first_insert), 'ss')
RETURNING user_id
)
insert into sample2 ( id ,adddetails)
values
( (select user_id from first_insert), 'ss');
As the generated id from the insert into sample2 is not needed, I removed the returning clause from the last insert.
Typically, you'd use a transaction to avoid writing complicated queries.
http://www.postgresql.org/docs/current/static/sql-begin.html
http://dev.mysql.com/doc/refman/5.7/en/commit.html
You could also use a CTE, assuming your Postgres tag is correct. For instance:
with sample_ids as (
insert into sample(firstname, lastname)
values('fai55','shaggk')
RETURNING id
), sample1_ids as (
insert into sample1(id, adddetails)
select id,'ss'
from sample_ids
RETURNING id, user_id
)
insert into sample2(id, user_id, value)
select id, user_id, 'val'
from sample1_ids
RETURNING id, user_id;
You could create an after insert trigger on the Sample table to insert into the other two tables.
The only issue i see with doing this is that you wont have a way of inserting adddetails it will always be empty or in this case ss. There is no way to insert a column into sample thats not actualy in the sample table so you cant send it along with the innital insert.
Another option would be to create a stored procedure to run your inserts.
You have the question taged mysql and postgressql which database are we talking about here?

Extract Row ID from Table - Insert Then Select

Is it Possible to extract the ID of the record being inserted in a table at the time of inserting dat particular record into that table ??? Reference to Sql Server
Read about INSERT with OUTPUT. This is in my experience the easiest way of achieving an atomic INSERT outputting an inserted value.
Example, assuming that Table contains an auto-incremented field named ID:
DECLARE #outputResult TABLE (ID BIGINT)
INSERT INTO Table
(
Field1,
Field2
)
OUPUT INSERTED.ID INTO #outputResult
VALUES
(
....
)
SELECT TOP 1 ID FROM #outputResult
You can select the ID afterwards with
SELECT ##IDENTITY
or
SELECT SCOPE_IDENTITY()