Merge and get Identity on Insert - sql-server

I need to merge new items in #temp_table into a table_a.
There is also a parent_table, which has a primary key identity column parent_table_id (and table_a has a corresponding foreign-key column for a parent_table_id). Each item in table_a points to a corresponding entry in the parent table.
So for each item in #temp_table, I need to insert into both table_a and parent_table.
The problem is, suppose I merge into the parent_table first, how do I get all of the corresponding parent_table_id items to set in all the table_a inserts? I was thinking of adding a parent_table_id column to #temp_table, initially set to null, then filling it up with values after the merge, but I'm not quite sure how to go about this. There is no other unique column in parent_table that can be used to select the new columns after they are inserted, other than the parent_table_id.

The following is a generic way of doing it (stripped down):
MERGE parent_table AS TARGET
USING #temp_table AS SOURCE
ON
(
TARGET.match_number = SOURCE.match_Number
)
WHEN NOT MATCHED THEN
INSERT
(
item1,
item2,
item3
)
VALUES
(
SOURCE.item1,
SOURCE.item2,
SOURCE.item3,
)
OUTPUT INSERTED.parent_table_id, SOURCE.reference_number INTO #Ids (parent_table_id, reference_number);
Results in #Ids containing all the parent table ids with other important info from the source which can be used elsewhere (i.e. for joining into table_a).

Related

MSSQL update set from output clause

Context
I got a temporary table which is filled/adjusted by users. Let's call the table tmp, with columns ID, updated_at, price, foreign_ID. Every time the user enters a new price, the price column is filled and the updated_at and ID are created automatically. foreign_ID is NULL until the record is processed to another table, when my foreign_ID should contain the ID of the other table.
Periodically I update a table with prices, let's call it prices. Here are all prices stored from different sources, among them from the tmp table. The prices table has the columns ID, updated_at, price.
question
I want to insert the data from my tmp table into prices table, and update the column foreign_ID with the corresponding ID from my prices table. How can I insert new rows in a table and update/set a IDs in another table?
My desired result after the periodic update is a new entry in the prices table with the new prices which were not yet processed, and a foreign_ID in my tmp table which corresponds with the ID in my prices table.
I know I can output the inserted IDs using the following query:
insert into prices
output inserted.ID
select price
from tmp;
I'm struggling to see how I can use the inserted.ID to update my tmp.foreign_ID column with the output above.
Help is appreciated!
You can also INSERT the values from the OUTPUT clause into another table as well, so if you need those you can still reference them.
Without proper sample data and behaviour, this is just an example but should, hopefully, set you on the right path as it shows you how to get the values from inserted into another object. You can then use that object to do the additional task(s) you need:
CREATE TABLE dbo.SomeTable (ID int IDENTITY(1,1),
SomeString varchar(10));
GO
DECLARE #IDs table (ID int);
INSERT INTO dbo.SomeTable (SomeString)
OUTPUT inserted.ID
INTO #IDs (ID)
VALUES('asdjgkde'),('sdflhdglf');
SELECT *
FROM #IDs;
GO
DROP TABLE dbo.SomeTable;

Insert from temp table to a table with identity column

I'm grabbing some rows from a table, manipulating them in a temp table, and then looking to insert them as new rows into my original table.
However, I'm running into an issue with the identity column, even when I don't have the identity column on my temp table. The identity column is an auto-incrementing int.
This seems like a simple thing I'm way overthinking.
select top 0 *
into #TestTable
from OriginalTable;
...
--insert and manipulate records
...
ALTER TABLE #TestTable
DROP COLUMN MyIdentityColumn;
DECLARE #InsertedRows TABLE (NewSeqNum INT);
INSERT INTO OriginalTable
OUTPUT MyIdentityColumn INTO #InsertedRows(NewSeqNum)
SELECT * FROM #TestTable
but I get this error:
An explicit value for the identity column in table 'OriginalTable' can only be specified when a column list is used and IDENTITY_INSERT is ON.
I absolutely do not want to set an explicit value, I want it to insert and give me the new identity (via #InsertedRows)
If you don't want to keep the id of inserted records, then you need to specify all your columns but the id column in the select. As general good practice, dont select *, always specify the columns you want to retrieve-insert.
INSERT INTO OriginalTable (col1, col2, col3...)
OUTPUT MyIdentityColumn INTO #InsertedRows(NewSeqNum)
SELECT (col1, col2, col3...) FROM #TestTable
If I'm understanding you, I think your problem is that you're trying to insert '*' into the original table - which means all of your columns from the temp table. Including your ID column (which you don't want to insert, because you're wanting it to auto-generate.)
Instead, I'd suggest doing something like this:
Select [ColumnB],[ColumnC],[ColumnD],[Etc] into your temp table
Select [ColumnB],[ColumnC],[ColumnD],[Etc] into your original table.
... aka, spell out the columns explicitly, and omit the Identity column.

Get values of IDENTITY values when inserting multiple rows into a table having instead of trigger

I'm inserting several rows into a table A which has an instead of insert trigger and an identity column.
Then I need to insert so many rows in a table B where each row hold a reference to the rows inserted in A.
The problem is, I can't use the output clause on A since, the identity will not be set (due to the trigger).
I know for one row I could use ##identity as long as the insertion of rows in A is the last insertion statement inside the trigger, but here I'm talking about multiple rows.
How can I achieve this?
I used code like this ( You CAN use table variable in OUTPUT clause )
declare #T table (requestID int);
INSERT <tableA> (<fields>)
OUTPUT inserted.RequestID into #T
VALUES( <fieldValues1> ),( <fieldValues2> ) ;
Insert <tableB> (ID) select RequestID from #T;

Create new table from Existing table With out identity property to be copied

I am using select * into to create a table from another table and used SET IDENTITY_INSERT ON for newly created table to accept data including identity column.
Now my question is that Is there any way to create a table (say TABLE A) from another existing table (say TABLE B) with out copying identity property of TABLE B to TABLE A.
Of course, let's say TABLEA looks like this:
CREATE TABLE TABLEA (
ID INT PRIMARY KEY IDENTITY(1, 1),
Column1 VARCHAR(50)
)
and let's assume that TABLEB looks the same. If we wanted to move data from TABLEB into TABLEA without moving the identity column we would write this statement:
INSERT INTO TABLEA (Column1)
SELECT Column1 FROM TABLEB
and this will cause every new row in TABLEA to get its own identity value.
But note, you can't issue a SELECT * FROM TABLEB because that would also select the ID column. You have to list out all of the fields you want individually. However, generally speaking, I think a lot of very experienced DBA's and programmers would say that SELECT * FROM Table is really dangerous because if the schema changes everything breaks. You really want to always be specific.
SELECT STUFF((SELECT ', ' + c.name FROM sys.columns c where c.object_id = OBJECT_ID('dbo.TABLE_NAME') and c.is_identity <> 1 FOR XML PATH('')),1, 2, '') AS CSVColumn
This will give you a comma separated list of columns of each table. Copy these statements into notepad to create a script that you can run.

In an OUTPUT clause in an INSERT trigger, is it possible to reference both INSERTED tables?

On the creation of a new record in a table, I need to create a record in each of two other tables (b and c). The trick is that the two new records need to have the same PK value, which must be a UNIQUEIDENTIFIER and is therefore generated using NEWID() and has no relation to the key of the original record. So, what I want to do in the INSERT TRIGGER looks something like this:
INSERT INTO [b] ([bKey], [Foo])
OUTPUT inserted.[bKey] [cKey], i.[Bar] INTO [c]
SELECT NEWID(), i.[Foo] FROM inserted i
However, this seems to be illegal (In an OUTPUT clause in an INSTEAD OF INSERT trigger, is it possible to reference both INSERTED tables?). Is there any way to do this other than by using a CURSOR and a variable for the result of the NEWID()?
The OUTPUT clause of an INSERT statement cannot reference any tables other than the inserted pseudo table of the output clause - see the notes on from_table_name:
Is a column prefix that specifies a table included in the FROM clause of a DELETE, UPDATE, or MERGE statement that is used to specify the rows to update or delete.
I think you can use a table variable/temporary table to achieve your goal:
DECLARE #tmp TABLE (
[bKey] …,
[Foo] …,
[Bar] …
);
INSERT INTO #tmp ([bKey], [Foo], [Bar])
SELECT NEWID(), [Foo], [Bar] FROM inserted;
INSERT INTO [b] ([bKey], [Foo])
SELECT [bKey], [Foo] FROM #tmp;
INSERT INTO [c] ([cKey], [Bar])
SELECT [bKey], [Bar] FROM #tmp;

Resources