How do I use an INSERT statement's OUTPUT clause to get the identity value? - sql

If I have an insert statement such as:
INSERT INTO MyTable
(
Name,
Address,
PhoneNo
)
VALUES
(
'Yatrix',
'1234 Address Stuff',
'1112223333'
)
How do I set #var INT to the new row's identity value (called Id) using the OUTPUT clause? I've seen samples of putting INSERTED.Name into table variables, for example, but I can't get it into a non-table variable.
I've tried OUPUT INSERTED.Id AS #var, SET #var = INSERTED.Id, but neither have worked.

You can either have the newly inserted ID being output to the SSMS console like this:
INSERT INTO MyTable(Name, Address, PhoneNo)
OUTPUT INSERTED.ID
VALUES ('Yatrix', '1234 Address Stuff', '1112223333')
You can use this also from e.g. C#, when you need to get the ID back to your calling app - just execute the SQL query with .ExecuteScalar() (instead of .ExecuteNonQuery()) to read the resulting ID back.
Or if you need to capture the newly inserted ID inside T-SQL (e.g. for later further processing), you need to create a table variable:
DECLARE #OutputTbl TABLE (ID INT)
INSERT INTO MyTable(Name, Address, PhoneNo)
OUTPUT INSERTED.ID INTO #OutputTbl(ID)
VALUES ('Yatrix', '1234 Address Stuff', '1112223333')
This way, you can put multiple values into #OutputTbl and do further processing on those. You could also use a "regular" temporary table (#temp) or even a "real" persistent table as your "output target" here.

Related

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.

While updating table1, how do I INSERT to table2 for every change in table 1?

I have a MEMBER table and NOTIFICATION table. On client side, I list all of the records in MEMBER table and there is a points column and this is shown as text input. So after I change the values for some members, I can click save button and this will update the records in my MEMBER table that's all right,
But the thing I want to accomplish is for every record whose points value has changed I want to INSERT a record in my notifications table.
I couldn't think of anything, how can I approach to this problem?
For notifications I made 3 tables by following the article in here
Use the output clause instead of trigger, they are bad.
You need the condition "where data_old <> data_new" case if you updated a column with the same value, SQL Server marked it as changed, even if the value hasn't changed
create table #example (id int identity(1,1) not null, data nvarchar(max));
insert into #example (data) values ('value 1'),('value 2'), ('value 3');
create table #audit (id int, data_old nvarchar(max), data_new nvarchar(max), [When] datetime not null default (getdate()));
insert into #audit (id, data_old, data_new)
select id, data_old, data_new
from (
update #example
set data = 'value changed'
output inserted.id, deleted.data as data_old, inserted.data as data_new
where id = 2
)changed (id, data_old, data_new)
where data_old <> data_new
select * from #audit
will result with this in #audit :
You have described what a trigger does.
create trigger trig_member_insert on members after update
as
begin
insert into notifications ( . . . )
select . . ., i.points as new_points u.points as old_points -- what you want to insert
from inserted i join
updated u
on i.member_id = u.member_id
where u.points <> i.points
end;
Storing something called "points" as a string seems like a very poor choice. It sounds like a number.

Select row just inserted without using IDENTITY column in SQL Server 2012

I have a bigint PK column which is NOT an identity column, because I create the number in a function using different numbers. Anyway, I am trying to save this bigint number in a parameter #InvID, then use this parameter later in the procedure.
ScopeIdentity() is not working for me, it saved Null to #InvID, I think because the column is not an identity column. Is there anyway to select the record that was just inserted by the procedure without adding an extra ID column to the table?
It would save me a lot of effort and work if there is a direct way to select this record and not adding an id column.
insert into Lab_Invoice(iID, iDate, iTotal, iIsPaid, iSource, iCreator, iShiftID, iBalanceAfter, iFileNo, iType)
values (dbo.Get_RI_ID('True'), GETDATE(),
(select FilePrice from LabSettings), 'False', #source, #user, #shiftID, #b, #fid, 'Open File Invoice');
set #invID = CAST(scope_identity() AS bigint);
P.S. dbo.Get_RI_ID('True') a function returns a bigint.
Why don't you use?
set #invId=dbo.Get_RI_ID('True');
insert into Lab_Invoice(iID,iDate,iTotal,iIsPaid,iSource,iCreator,iShiftID,iBalanceAfter,iFileNo,iType)
values(#invId,GETDATE(),(select FilePrice from LabSettings),'False',#source,#user,#shiftID,#b,#fid,'Open File Invoice');
You already know that big id value. Get it before your insert statement then use it later.
one way to get inserted statement value..it is not clear which value you are trying to get,so created some example with dummy data
create table #test
(
id int
)
declare #id table
(
id int
)
insert into #test
output inserted.id into #id
select 1
select #invID=id from #id

Confusion about Stored Procedure

I have written a stored procedure for inserting data into my table. These are my table's columns with their datatype:
Ad nvarchar(150),
Yazar nvarchar(150),
SayfaSayisi smallint,
KategoriId int
Gmc datetime,
HostName nvarchar(150)
The problem is that Gmc and HostName have their own default values. So I can't use these two in the stored procedure.
Gmc ---> GetDate() (to get insert date)
HostName --> Host_Name( )
So when I execute the query I am getting this error.
There are more columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement
This is the query
Create proc Kitap_Insert
#Ad nvarchar(150),
#Yazar nvarchar(150),
#SayfaSayisi smallint,
#KategoriId int
Gmc datetime,
HostName nvarchar(150)
as
Insert into Kitap(Id, Ad, Yazar, SayfaSayisi, KategoriId)
values(#Ad, #Yazar, #SayfaSayisi, #KategoriId)
What is the proper way of doing this?
You need remove ID from insert list
Insert into Kitap(Ad,Yazar,SayfaSayisi,KategoriId)
values(#Ad,#Yazar,#SayfaSayisi,#KategoriId)
or add a value for it as below
Insert into Kitap(Id,Ad,Yazar,SayfaSayisi,KategoriId)
values(#ID, #Ad,#Yazar,#SayfaSayisi,#KategoriId)
Instead of :
Insert into Kitap(Id,Ad,Yazar,SayfaSayisi,KategoriId)
values(#Ad,#Yazar,#SayfaSayisi,#KategoriId)
Use:
INSERT INTO Kitap(Ad,Yazar,SayfaSayisi,KategoriId)
VALUES (#Ad,#Yazar,#SayfaSayisi,#KategoriId)
You are asking SQL engine that you will provide id (an additional field) as well (field that doesn't exist in the table or is an auto increment field) and you are not providing the value for the same and hence your error here are more columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement
So remove additional Id from your insert query.
The error you are getting because you tried to insert value into more column names than specified in Values Clause.
If you have ID column as Auto-increment field in table so you dont have to include that ID column in so your insert query will be like this:-
Insert into Kitap
(Ad,Yazar,SayfaSayisi,KategoriId)
values
(#Ad,#Yazar,#SayfaSayisi,#KategoriId)
If you don't have ID column as Auto-increment field in table so you provide value to that id column also in Value Clause so your insert query will be like this:-
NOTE:-
You have to calculate and Set Value to #Id variable before using it in Insert Query
Declare #Id as INT
SET #ID = ---- set here with some value which will become Primary key(I think)
Insert into Kitap
(Id,Ad,Yazar,SayfaSayisi,KategoriId)
values
(#Id, #Ad,#Yazar,#SayfaSayisi,#KategoriId)

How do I return a new IDENTITY column value from an SQLServer SELECT statement?

I'm inserting into an SQLServer table with an autoincrementing key field. (I believe this is called an IDENTITY column in SQLServer.)
In Oracle, I can use the RETURNING keyword to give my INSERT statement a results set like a SELECT query that will return the generated value:
INSERT INTO table
(foreign_key1, value)
VALUES
(9, 'text')
RETURNING key_field INTO :var;
How do I accomplish this in SQLServer?
Bonus: Okay, nice answers so far, but how do I put it into a single statement, if possible? :)
In general, it can't be done in a single statement.
But the SELECT SCOPE_IDENTITY() can (and should) be placed directly after the INSERT statement, so it's all done in the same database call.
Example:
mydb.ExecuteSql("INSERT INTO table(foreign_key1, value) VALUES(9, 'text'); SELECT SCOPE_IDENTITY();");
You can use OUTPUT, but it has some limitations you should be aware of:
http://msdn.microsoft.com/en-us/library/ms177564.aspx
SELECT SCOPE_IDENTITY()
Edit: Having a play...
If only the OUTPUT clause supported local variables.
Anyway, to get a range of IDs rather than a singleton
DECLARE #Mytable TABLE (keycol int IDENTITY (1, 1), valuecol varchar(50))
INSERT #Mytable (valuecol)
OUTPUT Inserted.keycol
SELECT 'harry'
UNION ALL
SELECT 'dick'
UNION ALL
SELECT 'tom'
Edit 2: In one call. I've never had occasion to use this construct.
DECLARE #Mytable TABLE (keycol int IDENTITY (1, 1), valuecol varchar(50))
INSERT #Mytable (valuecol)
OUTPUT Inserted.keycol
VALUES('foobar')
In addition to ##IDENTITY, you should also look into SCOPE_IDENTITY() and IDENT_CURRENT(). You most likely want SCOPE_IDENTITY(). ##IDENTITY has a problem in that it might return an identity value created in a trigger on the actual table that you're trying to track.
Also, these are single-value functions. I don't know how the Oracle RETURNING keyword works.
SCOPE_IDENTITY
It depends on your calling context.
If you're calling this from client code, you can use OUTPUT and then read the value returned.
DECLARE #t TABLE (ColID int IDENTITY, ColStr varchar(20))
INSERT INTO #t (ColStr)
OUTPUT Inserted.ColID
VALUES ('Hello World')
Result:
ColID
-----------
1
If you're wrapping this in a stored procedure, using OUTPUT is more work. There, you'll want to use SCOPE_IDENTITY(), but you can't do it in a single statement. Sure, you can put multiple statements on a single line with a ';' separator, but that's not a single statement.
DECLARE #idValue int
DECLARE #t TABLE (ColID int IDENTITY, ColStr varchar(20))
INSERT INTO #t (ColStr) VALUES ('Hello World')
SELECT #idValue = SCOPE_IDENTITY()
Result: #idValue variable contains identity value. Use an OUTPUT parameter to return the value.
You can use OUTPUT INTO, which has the additional benefits of being able to capture multiple identities inserted.
INSERT INTO table(foreign_key1, value)VALUES(9, 'text');SELECT ##IDENTITY;