Update table column with primary key after insert (in one statement) - sql

Using an update statement, how can i directly set a column value to the primary key of an insert statement? I need this as one statement.
I know the following is wrong, but it helps get my idea through:
update AppNationalities
set CountrySelectionID = (
select [INSERTED.pkID] from
(
insert into CountrySelections
output INSERTED.pkID
values(CountryID, 'test', 0)
)
)

Put the values into a temporary table:
declare #ids table (pkID int);
insert into CountrySelections
output INSERTED.pkID into #ids
values (CountryID, 'test', 0);
update AppNationalities
set CountrySelectionID = i.id
from #ids i;
I don't think the output clause is allowed in the FROM clause of an UPDATE or DELETE statement.

Related

Assign values from a table variable to each row of a table?

I have a table (Reference table) that will hold unique values (uniqueidentifer types).
I have two million users and I need to generate a unique value for each one in this Reference table.
As I create them, I would like to capture these unique values and assign them to each user in another table, called a User table.
Below is my attempt: I have created a table variable called #ReferenceIds. How can I take #ReferenceIds and assign each unique value to a separate row in the User table?
create procedure create_reference_ids
#numberOfNewAccounts int
DECLARE #ReferenceIds TABLE (Id uniqueidentifier)
set #numberOfNewAccounts = 2000000
as
begin
while #numberOfNewAccounts > 0
begin
insert into Reference (0,0,#UtcNow,#UtcNow)
OUTPUT Inserted.Id INTO #ReferenceIds
set #numberOfNewAccounts = #numberOfNewAccounts - 1
end
end
exec create_reference_ids
Use a merge statement to insert the exact number of reference values as you have users, and output the new Ids into a table variable which links your new reference ids to your existing user ids. Then carry out an update on your users table.
DECLARE #NewId TABLE (UserId int, ReferenceId int);
-- Using Merge for insert is the only way to get values from columns in the output table which don't exist in the Target table
MERGE INTO dbo.Reference AS Target
USING dbo.[User] AS Source
ON 1 = 0 -- Force an insert regardless
WHEN NOT MATCHED THEN
-- Best practice is to always explicitly name your columns
INSERT (Col1, Col2, Col3, Col4)
VALUES (0, 0, #UtcNow, #UtcNow)
OUTPUT Source.Id, Inserted.Id
INTO #NewId (UserId, ReferenceId);
UPDATE U SET
ReferenceId = I.ReferenceId
FROM dbo.[User] U
INNER JOIN #NewId I on I.UserId = U.Id;

SQL Insert ,Update using Merge Store Procedure

I need to do a bulk Insert and/or Update for a target table in a SQL database. I have already tried the Merge stored procedure. In the target table I have a composite key.
I need to generate a pattern for first field (of the key) while inserting. I have tried a user-defined function that returns a pattern key which is unique for each of the rows.
My question is, how do I incorporate this function into a query that would auto-generate the key and insert the respective fields for each record?
TargetTable is my destination table in database and it has two columns - Key1(Bigint),Key2(int). Once again, this is a composite key.
Note: I only want to generate the key for the first field/column.
Here's my stored procedure:
Merge Targettable as T
Using SourceTable as s
ON s.Key1 = T.Key1 and
s.Key2=T.Key2
WHEN MATCHED THEN UPDATE
SET T.UserName = S.UserName
WHEN NOT MATCHED THEN
INSERT (Key1, Key2, UserName)
VALUES (dbo.UserDefiendFunction(#parama1),Key2,userName)
UserDefinedFunction returns the pattern i want.
Here's my User Defined Function:
Create function [dbo].[UserDefinedFunction] (
#Param1 int)
returns BIGINT
AS Begin
DECLARE #ResultVar BIGINT
SET #ResultVar=CONVERT(BIGINT, (SELECT Cast(#Param1 AS VARCHAR(10))
+ '' + Format((SELECT Count(userName)+1 FROM [dbo].[TableName]), '0')) )
RETURN #ResultVar
END
Please help me out with this. Thanks in advance.
IF EXISTS (SELECT * FROM Table1 join table 2 on Column1='SomeValue')
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
ELSE
insert into ods..Table1 (Columname)
select [DatabaseName].[dbo].[UserDefinedFunction] (#paramater) as ColumnName

SQL Output if row exists, insert and output if it does not exist

I basically want to insert something and use the OUTPUT function to get some values out of the inserted line. That's easy.
But I also want my query to get these values even if there has nothing been inserted because the primary already exists.
DECLARE #existingId bigint;
IF EXISTS(SELECT #existingId = Id FROM MyTable WHERE Name = #Name)
OUTPUT #existingId;
RETURN;
INSERT INTO MyTable (Name) OUTPUT INSERTED.Id VALUES (#Name);
This just always gives me Incorrect syntax near '='.
Any ideas how to achieve this behavior?
output takes a table, not a value. So the code you are striving to write should look more like this:
DECLARE #out table (existingid bigint);
INSERT INTO #out(existingid)
SELECT Id FROM MyTable WHERE Name = #Name;
IF EXISTS (SELECT * FROM #out)
RETURN;
INSERT INTO MyTable (Name)
OUTPUT INSERTED.Id INTO #out
VALUES (#Name);
This code, however, has race conditions. Because someone could insert Name between the check for the existence and the insert. To really fix this, you should use try/catch and have a unique index on name. Here is an example of the code:
DECLARE #out table (existingid bigint);
BEGIN TRY
INSERT INTO MyTable (Name)
OUTPUT INSERTED.Id INTO #out
VALUES (#Name);
RETURN
END TRY
BEGIN CATCH -- assume there is a duplicate although there could be other problems
INSERT INTO #out(existingid)
SELECT Id FROM MyTable WHERE Name = #Name;
END CATCH;
The following code creates the unique index:
create unique index idx_mytable_name on mytable(name);
I believe you are missing A opening and closing parenthesis, try:
DECLARE #existingId bigint;
IF EXISTS(SELECT #existingId =( Id FROM MyTable WHERE Name = #Name))
OUTPUT #existingId;
RETURN;
INSERT INTO MyTable (Name) OUTPUT INSERTED.Id VALUES (#Name);

How to get a value of identity column using OUTPUT - SQL Server

I have a table and a trigger
create table test(id int not null identity(1,1) primary key, data int);
create trigger insteadTestInsert ON test INSTEAD OF INSERT
AS
BEGIN
INSERT INTO test(data) select data FROM inserted;
END;
When trigger is enabled, the following query
declare #tmp_table table(id int, int_val int);
insert into test(data)
output inserted.* into #tmp_table
values (10);
select * from #tmp_table;
returns id = 0, int_val = 10 .
If I disable(or drop) the trigger, the query returns the proper value of id.
How to make OUTPUT insert proper results into table variable?
From MSDN
Columns returned from OUTPUT reflect
the data as it is after the INSERT,
UPDATE, or DELETE statement has
completed but before triggers are
executed.
So the problem is that before your trigger was executed inserted didn't have id set.
Even if remove content of the trigger like this
create trigger insteadTestInsert on test instead of insert
as
begin
return;
end
you will see that inserted is still populated although nothing was inserted into the table. Basically inserted in output statement matches inserted inside of the trigger.
This one actually works.
declare #tmp_table table(seq int identity, id int, int_val int);
insert into test(data)
output inserted.data into #tmp_table(int_val)
values (11),(12),(13);
update #tmp_table set id = seq + ##identity - ##rowcount
select * from #tmp_table;
select top 2 * from test order by id desc;
The restriction is that you must NOT have any other triggers on the table test that would "corrupt" the ##identity variable.
This is a hack, but it works:
declare #tmp_table table(id int, int_val int);
insert into test(data)
output ##IDENTITY + 1, inserted.data into #tmp_table
values (10);
select * from #tmp_table;
See http://msdn.microsoft.com/en-us/library/ms190315.aspx for details on using ##IDENTITY.

Getting the identity of the row I just inserted

I've got two tables that are linked with foreign keys. I need to do a few inserts on one table and then use the identity column values are part of my next batch of insert statements. This all has to be done through SQL.
I've been reading about SCOPE_IDENTITY() but all the examples I'm seeing are using ASP/PHP/Whatever to do the substitution in the next batch of inserts, I dont have this option.
Any pointers appreciated.
Use
SCOPE_IDENTITY() - Function
instead of
##IDENTITY Variable -
otherwise you get the result of the last inserted identity - if there is a trigger on the table than does inserting somewhere you get the wrong result back (the value inserted by the trigger and not by your statement). Scope_Identity returns the identity of your statement and that is what you normally want.
IN SQl Server 2008 you can also use the OUTPUT clause.
DECLARE #output TABLE (myid INT)
INSERT mytable (field1, field2)
OUTPUT inserted.myid INTO #output
VALUES ('test', 'test')
SELECT * FROM #output
What makes this espcially valuable is if you use it to insert a bunch of records instead of one you can get all the identities, You can also return any of the other fields you might need.
something like:
DECLARE #output TABLE (myid INT, field1 datetime)
INSERT mytable (field1, field2)
OUTPUT inserted.myid, inserted.field1 INTO #output
Select '20100101', field3 from mytable2
SELECT * FROM #output
You can do the same with SQL or TSQL. Just assign the identify column as soon as you do the insert.
-- Variable to hold new Id
Declare #NewId int
--Insert some values in to create a new ID
Insert Into dbo.MyTable1 (Col1)
Values (#NewValue)
-- Grab the new Id and store it in the variable
Select #NewId = Scope_Identity()
--Insert the new Id in to another table
Insert Into dbo.AnotherTable (Col1)
Values (#NewId)
You can use
SELECT SCOPE_IDENTITY() [Iden]
After the insert statement in the same block. This should work.