Merge SQL INSERT with Reference Table - sql

I need to synchronize two tables.
TableA
Id Name
TableB
Id Name RefID --It's a Foreign key, defined as primary key in Table "TableReference"
TableReference
RefID -- Identity Column, auto increment
I need to merge TableA and TableB in such a way that on each insert in TableB, a value should be inserted into TableReference and that inserted value should be copied into RefId column of TableB.
What I am doing?
I am using SSIS hence I need to have a SSIS based solution OR SQL based solution. I know how to merge tables using Merge SQL command but I am not able to insert a value into TableRef and copy it back to TableB. Could not figure out how i can accomplish this. SQL user-defined functions don't allow INSERT so I can't use it.
Merge TabaleB T
Using Table A S
On S.Id=T.Id
WHEN MATCHED THEN
UPDATE
T.ID=S.ID,
T.NAME=S.NAME
WHEN NOT MATCHED BY TARGET THEN
INSERT(S.ID,S.NAME, {Somehow here i need a function call that inserts in TableRef and Returns SCOPE_IDENTITY})
The problem is T-SQL functions don't allow INSERT and a stored procedure can't be called here as Merge doesn't allow any TSQL thing other than INSERT after WHEN NOT MATCHED BY TARGET THEN.

Are you able to add a TRIGGER on your TableB. If so, one option would be to use the INSERTED row and go from there.
Maybe something like this (untested):
CREATE TRIGGER dbo.tr_TableB
ON dbo.TableB
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT TableReference DEFAULT VALUES;
DECLARE #RefId INT;
SELECT #RefId = SCOPE_IDENTITY();
UPDATE t1
SET t1.RefId = #RefId
FROM dbo.TableB AS t1
INNER JOIN INSERTED AS i
ON i.Id= t1.Id
END
GO
Good luck.

Related

Insert bulk data into two related tables with foreign keys from another table

I have imported some data to a temp SQL table from an Excel file. Then I have tried to insert all rows to two related tables. Simply like this: There are Events and Actors tables with many to many relationship in my database. Actors are already added. I want to add all events to Events table and then add relation(ActorId) for each event to EventActors tables.
(dbo.TempTable has Title, ActorId columns)
insert into dbo.Event (Title)
Select Title
From dbo.TempTable
insert into dbo.EventActor (EventId, ActorId)
Select SCOPE_IDENTITY(), ActorId --SCOPE_IDENTITY() is for EventId
From dbo.TempTable
When this code ran, all events inserted into Events, but the relations didn't inserted into EventActors because of Foreign Key error.
I think there should be a loop. But I am confused. I don't want to write C# code for this. I know there would be a simple but advanced solution trick for this in SQL Server. Thanks for your help.
Use the output clause to capture the new IDs, with a merge statement to allow capture from both source and destination tables.
Having captured this information, join it back to the temp table for the second insert.
Note you need a unique id per row, and this assumes 1 row in the temp table creates 1 row in both the Event and the EventActor tables.
-- Ensure every row has a unique id - could be part of the table create
ALTER TABLE dbo.TempTable ADD id INT IDENTITY(1,1);
-- Create table variable for storing the new IDs in
DECLARE #NewId TABLE (INT id, INT EventId);
-- Use Merge to Insert with Output to allow us to access all tables involves
-- As Insert with Output only allows access to columns in the destination table
MERGE INTO dbo.[Event] AS Target
USING dbo.TempTable AS Source
ON 1 = 0 -- Force an insert regardless
WHEN NOT MATCHED THEN
INSERT (Title)
VALUES (Source.Title)
OUTPUT Source.id, Inserted.EventId
INTO #NewId (id, EventId);
-- Insert using new Ids just created
INSERT INTO dbo.EventActor (EventId, ActorId)
SELECT I.EventId, T.ActorId
FROM dbo.TempTable T
INNER JOIN #NewId I on T.id = T.id;

After insert trigger for updating a column

I am writing an after insert trigger trying to find a solution to this problem here:
https://stackoverflow.com/questions/19355644/dead-ends-all-around-trying-to-update-geography-column
What I am unsure of is how to write the trigger to take into consideration multiple records as explained here as a potential you need to code for.
So far I had this but it applies only to a single record so if the table had 100 records inserted in a batch 99 would not be updated. This is my understanding so far and may not be correct.
create trigger tri_inserts on [dbo].[Address]
after insert
as
set nocount on
update Address
SET AddyGeoCode = GEOGRAPHY::Point(inserted.AddyLat, inserted.Addylong, 4326)
GO
Would I say join to the inserted table to discover / update all the new records?
In case it is needed my Address table schema is AddyLat & AddyLong decimal(7,4) and AddyGeoCode Geography.
TIA
Yes, you need to join on inserted table.
UPDATE a
SET a.AddyGeoCode = GEOGRAPHY::Point(a.AddyLat, a.Addylong, 4326) --you can use AddyLat&Long from either a or i
FROM Address a
INNER JOIN inserted i ON a.id = i.id --whatever are your PK columns

SQL Server trigger on update with select then insert into multiple tables

I am trying to create a trigger on update of a column and insert rows into other tables. The data is coming from a SELECT with multiple joins and needs to be inserted into multiple tables.
My question is, is it best practice to insert the values into variables before the insert? I have never created a trigger like this before.
CREATE TRIGGER ship_trigger ON dbo.Orders
FOR UPDATE
AS
SET NOCOUNT ON
IF ( UPDATE(OrderStatusId) AND OrderStatusId == 1)
BEGIN
SELECT
FROM
JOIN
JOIN
WHERE
I am just looking to understand the most efficient way to insert the data into the other tables
Thanks!
Assuming SQL Server (the syntax suggests so), it isn't a best practice to insert the values into variables first, what would be the point of doing that?. And the only way that you could actually do that would be on table variables or if you update only one row, since the triggers gets executed once for all the rows that got affected by your UPDATE, and those rows are available to you on the INSERTED pseudo table. So, your trigger would look something like this:
CREATE TRIGGER ship_trigger ON dbo.Orders
FOR UPDATE
AS
SET NOCOUNT ON
IF ( UPDATE(OrderStatusId) AND OrderStatusId = 1)
BEGIN
INSERT INTO SomeTable(Col1, Col2)
SELECT Col1, Col2
FROM INSERTED
END

How to use update trigger to update another table?

I am new to triggers and want to create a trigger on an update of a column and update another table with that value.
I have table1 with a year column and if the application updates that year column I need to update table 2 with the year the same year.
ALTER TRIGGER [dbo].[trig_UpdateAnnualYear]
ON [dbo].[table1]
AFTER UPDATE
AS
if (UPDATE (intAnnualYear))
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
Update table2 set AnnualYear = intAnnualYear where table2.ID = table1.ID
END
You don't reference table1 inside the trigger. Use the inserted pseudo table to get the "after" values. Also remember that an update can affect multiple rows.
So replace your current update statement with
UPDATE table2
SET table2.annualyear = inserted.intannualyear
FROM table2
JOIN inserted
ON table2.id = inserted.id
You only need to update the records in table2 if the column intannualyear is involved. Also, this is an alternative UPDATE syntax across two tables from what Martin has shown
IF UPDATE(intannualyear)
UPDATE table2
SET annualyear = inserted.intannualyear
FROM inserted
WHERE table2.id = inserted.id
According to this question, if there's only one "downstream" table then another option with a properly defined foreign key relation would be Cascaded update.
To supplement the above answers, if you have to check more than one column you can use a INNER JOIN between inserted and deleted, or several UPDATE() calls:
IF ( UPDATE(Col1) OR UPDATE(Col2) ) BEGIN ...

Sql Server trigger insert values from new row into another table

I have a site using the asp.net membership schema. I'd like to set up a trigger on the aspnet_users table that inserted the user_id and the user_name of the new row into another table.
How do I go about getting the values from the last insert?
I can select by the last date_created but that seems smelly. Is there a better way?
try this for sql server
CREATE TRIGGER yourNewTrigger ON yourSourcetable
FOR INSERT
AS
INSERT INTO yourDestinationTable
(col1, col2 , col3, user_id, user_name)
SELECT
'a' , default , null, user_id, user_name
FROM inserted
go
You use an insert trigger - inside the trigger, inserted row items will be exposed as a logical table INSERTED, which has the same column layout as the table the trigger is defined on.
Delete triggers have access to a similar logical table called DELETED.
Update triggers have access to both an INSERTED table that contains the updated values and a DELETED table that contains the values to be updated.
You can use OLDand NEW in the trigger to access those values which had changed in that trigger. Mysql Ref
In a SQL Server trigger you have available two psdeuotables called inserted and deleted. These contain the old and new values of the record.
So within the trigger (you can look up the create trigger parts easily) you would do something like this:
Insert table2 (user_id, user_name)
select user_id, user_name from inserted i
left join table2 t on i.user_id = t.userid
where t.user_id is null
When writing triggers remember they act once on the whole batch of information, they do not process row-by-row. So account for multiple row inserts in your code.
When you are in the context of a trigger you have access to the logical table INSERTED which contains all the rows that have just been inserted to the table. You can build your insert to the other table based on a select from Inserted.
Create
trigger `[dbo].[mytrigger]` on `[dbo].[Patients]` after update , insert as
begin
--Sql logic
print 'Hello world'
end