I have 'inherited' a brilliant piece of TSQL code that does this:
Obviously this sucks (performance & elegance reasons)!!
Question At first this looks like a standard case of MERGE usage. I tried doing:
MERGE [dbo].[TableA] AS Target
USING <cursor data set as a select statement> as Src on target.IDA = Src.IDA
WHEN MATCHED
//update
WHEN NOT MATCHED
//insert <------ Fails because obviously a new IDB is required
Also tried various approaches like a nested select that sends IDB on the OUTPUT
but it fails because IDB is a PK.
Other kinds of merges also failed eg:
MERGE Table A with <cursor data set as a select statement>
...
MERGE Table A with Table B
WHEN NOT MATCHED
//insert on Table A
WHEN NOT MATCHED
// Update Table B
Does anyone have an idea on this? Essentially I think if we generalise the question would be:
Can I insert and return the PK in one statement that can be nested in other statements
Thanks in advance for any replies
George
If you have an autogenerated PK on TableB, you can use code similar to this. Otherwise, just change the INSERT into TableA to grab the PK from TableB first.
DECLARE @OldData CHAR(10)
SET @OldData = 'Old'
DECLARE @NewData CHAR(10)
SET @NewData = 'New'
CREATE TABLE #TableA
(
IDA INT IDENTITY(1,1) PRIMARY KEY,
IDB INT NOT NULL,
DataA CHAR(10)
)
CREATE TABLE #TableB
(
IDB INT IDENTITY(1,1) PRIMARY KEY,
DataB CHAR(10)
)
DECLARE @IDsToUpsert TABLE
(
ID INT
)
-- Add test values for existing rows
INSERT INTO #TableB
OUTPUT INSERTED.IDB, @OldData
INTO #TableA
SELECT @OldData UNION ALL
SELECT @OldData UNION ALL
SELECT @OldData UNION ALL
SELECT @OldData
-- Add test values for the rows to upsert
INSERT INTO @IDsToUpsert
SELECT 1 UNION -- exists
SELECT 3 UNION -- exists
SELECT 5 UNION -- does not exist
SELECT 7 UNION -- does not exist
SELECT 9 -- does not exist
-- Data Before
SELECT * From #TableA
SELECT * From #TableB
DECLARE rows_to_update CURSOR
FOR SELECT ID FROM @IDsToUpsert
DECLARE @rowToUpdate INT
DECLARE @existingIDB INT
OPEN rows_to_update;
FETCH NEXT FROM rows_to_update
INTO @rowToUpdate;
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRANSACTION
IF NOT EXISTS
(
SELECT 1 FROM #TableA WITH (UPDLOCK, ROWLOCK, HOLDLOCK)
WHERE IDA = @rowToUpdate
)
BEGIN
-- Insert into B, then insert new val into A
INSERT INTO #TableB
OUTPUT INSERTED.IDB, INSERTED.DataB
INTO #TableA
SELECT @NewData
-- Change code here if PK on TableB is not autogenerated
END
ELSE
BEGIN
-- Update
UPDATE #TableA
SET DataA = @NewData
WHERE IDA = @rowToUpdate
END
COMMIT TRANSACTION
FETCH NEXT FROM rows_to_update
INTO @rowToUpdate;
END
CLOSE rows_to_update;
DEALLOCATE rows_to_update;
SELECT * FROM #TableA
SELECT * FROM #TableB
DROP TABLE #TableA
DROP TABLE #TableB
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With