I have two SQL Server tables where I need to add records from one table to the next. If the unique identifier already exists in the target table, then update the record to the data coming from source table - If the unique identifier doesn't exist, then insert the entire new record into the target table.
I seem to have gotten the initial part to work where I update the records in target table but the the part where I would INSERT new records does not seem to be working.
if exists (
select 1
from SCM_Top_Up_Operational O
join SCM_Top_Up_Rolling R ON O.String = R.string
)
begin
update O
set O.Date_Added = R.Date_Added,
O.Real_Exfact = R.Real_Exfact,
O.Excess_Top_Up = R.Excess_Top_Up
from SCM_Top_Up_Operational O
join SCM_Top_Up_Rolling R on O.String = R.String
where O.String = R.string and R.date_added > O.date_added
end
else
begin
insert into SCM_Top_Up_Operational (String,Date_Added,Real_Exfact,Article_ID,Excess_Top_Up,Plant)
select String,Date_Added,Real_Exfact,Article_ID,Excess_Top_Up,Plant
from SCM_Top_Up_Rolling
end
If I followed you correctly, you should be able to solve this with a single SQL query, using SQL Server MERGE syntax, available since SQL Server 2008.
From the documentation:
Runs insert, update, or delete operations on a target table from the results of a join with a source table. For example, synchronize two tables by inserting, updating, or deleting rows in one table based on differences found in the other table.
Consider the following query:
MERGE
SCM_Top_Up_Operational O
USING SCM_Top_Up_Rolling R ON (O.String = R.string)
WHEN MATCHED
THEN UPDATE SET
O.Date_Added = R.Date_Added,
O.Real_Exfact = R.Real_Exfact,
O.Excess_Top_Up = R.Excess_Top_Up
WHEN NOT MATCHED BY TARGET
THEN INSERT ( String, Date_Added, Real_Exfact, Article_ID, Excess_Top_Up, Plant)
VALUES (R.String, R.Date_Added, R.Real_Exfact, R.Article_ID, R.Excess_Top_Up, R.Plant)
Related
I have two tables(src, tgt) on a dedicated sql pool in Azure Synapse, which both contain approximately 200 million records. Let's say they have columns A and B. I'm trying to update the field tgt.A with the value from src.A when tgt.B matches src.B. If src.B does not exist in tgt.B, insert the new record.
I tried using the MERGE statement as below:
MERGE tgt
USING src
ON tgt.B = src.B
WHEN MATCHED AND tgt.A <> src.A
THEN UPDATE SET tgt.A = src.A
WHEN NOT MATCHED
THEN INSERT (
A,B
)
Values
(
src.A, src.B
);
I also tried the insert and update statements separately as below:
INSERT INTO tgt
SELECT A, B
FROM src
WHERE NOT EXISTS(SELECT B FROM tgt WHERE tgt.B = src.B)
UPDATE tgt
SET tgt.A = src.A
WHERE EXISTS(SELECT B FROM tgt WHERE tgt.B = src.B)
For testing purpose, I took a smaller subset of tgt table containing 6 million records and source containing only 400k records. Still, with either of the above approaches, the stored procedure keeps executing beyond 1 hour where I cancel the execution. I noticed that with even smaller samples with 1k records in each table, it executes within a minute but struggles with large number of records. Please recommend the best approach to tackle the issue, can this be optimized?
Note: The source table is populated and dropped within the stored procedure and only the target table is saved with the updated records.
I’m trying to create a trigger to change the value of a column in table B if it finds the information in a column in table A.
An example of my database is below:
[TableA],
itemID
[TableB],
itemID
itemInStock
Once a user creates an entry in Table A declaring an itemID, the trigger needs to change the TableB.itemInStock column to ‘Yes’
I’m still learning SQL so excuse me if I’ve missed something, let me know if you need any more info.
I understand there are better ways of doing this but I've been told I need to do this using a trigger.
I've attempted a few different things, but as it stands nothing is working, below is the current solution I have however this updates all itemInStock rows to 'Yes', where as I only want the ones to update where the TableB.itemID matches the itemID entered in TableA.
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA] FOR
INSERT
AS
BEGIN
UPDATE [dbo].[TableB] set itemInStock = 'Yes' WHERE
TableB.itemID = itemID
END
Two problems -
you're not looking at the Inserted pseudo table which contains the
newly inserted rows
you're assuming the trigger is called once per row - this is not the
case, the trigger is called once per statement and the Inserted
pseudo table will contain multiple rows - and you need to deal with
that
So, your code should look like this -
ALTER TRIGGER [itemAvailability] ON [dbo].[TableA]
FOR INSERT
AS
UPDATE TB
SET itemInStock = 'Yes'
FROM [dbo].[TableB] TB JOIN inserted I
on TB.itemID = I.itemID
I have a table called dsReplicated.matDB and a column fee_earner. When that column is updated, I want to record two pieces of information:
dsReplicated.matDB.mt_code
dsReplicated.matDB.fee_earner
from the row where fee_earner has been updated.
I've got the basic syntax for doing something when the column is updated but need a hand with the above to get this over the line.
ALTER TRIGGER [dsReplicated].[tr_mfeModified]
ON [dsReplicated].[matdb]
AFTER UPDATE
AS
BEGIN
IF (UPDATE(fee_earner))
BEGIN
print 'Matter fee earner changed to '
END
END
The problem with triggers in SQL server is that they are called one per SQL statement - not once per row. So if your UPDATE statement updates 10 rows, your trigger is called once, and the Inserted and Deleted pseudo tables inside the trigger each contain 10 rows of data.
In order to see if fee_earner has changed, I'd recommend using this approach instead of the UPDATE() function:
ALTER TRIGGER [dsReplicated].[tr_mfeModified]
ON [dsReplicated].[matdb]
AFTER UPDATE
AS
BEGIN
-- I'm just *speculating* here what you want to do with that information - adapt as needed!
INSERT INTO dbo.AuditTable (Id, TriggerTimeStamp, Mt_Code, Old_Fee_Earner, New_Fee_Earner)
SELECT
i.PrimaryKey, SYSDATETIME(), i.Mt_Code, d.fee_earner, i.fee_earner
FROM Inserted i
-- use the two pseudo tables to detect if the column "fee_earner" has
-- changed with the UPDATE operation
INNER JOIN Deleted d ON i.PrimaryKey = d.PrimaryKey
AND d.fee_earner <> i.fee_earner
END
The Deleted pseudo table contains the values before the UPDATE - so that's why I take the d.fee_earner as the value for the Old_Fee_Earner column in the audit table.
The Inserted pseudo table contains the values after the UPDATE - so that's why I take the other values from that Inserted pseudo-table to insert into the audit table.
Note that you really must have an unchangeable primary key in that table in order for this trigger to work. This is a recommended best practice for any data table in SQL Server anyway.
I have 2 tables with same table structure. Table A is having all transaction with 3 unique key in each record. Table B have only condition base record only.
I want compare both tables if Table B has matching record than I want to update and Table B have not matching record than insert in Table B.
Can you please suggest best way to do it like ssis or any thing else
The easiest way is a MERGE statement:
MERGE INTO Table_B
USING Table_A
ON TableA.ID1 = Table_B.ID1 AND TableA.ID2 = Table_B.ID2 AND TableA.ID3 = Table_B.ID3
WHEN MATCHED THEN UPDATE SET A = Table_A.A, B = Table_A.B -- Etcetera...
WHEN NOT MATCHED THEN INSERT (A, B) VALUES (Table_A.a, Table_A.B) -- Etcetera...
WHEN NOT MATCHED BY SOURCE THEN DELETE -- If Necessary...
;
By the way, don't forget the ";" at the end. SQL Server doesn't usually need them, but a MERGE does.
Here is the SQL Query:
MERGE tblProductsSold
USING tblOrders on tblOrders.OrderID = tblProductsSold.txtOrderID
WHEN NOT MATCHED THEN
Insert ( txtOrderID, txtOrderdate, txtPartno, txtQty)
values
(SELECT tblItemsOnOrder.txtOrderID,
tblOrders.txtDateTime,
tblItemsOnOrder.txtPartNO,
tblItemsOnOrder.txtQTY
FROM tblOrders INNER JOIN tblItemsOnOrder
ON tblOrders.OrderID = tblItemsOnOrder.txtOrderID
WHERE tblOrders.txtIsConfirmed = '1'
)
OUTPUT $action ;
Desired Result: need to import orders with Products that are not already in the tblProductsSold table
You cannot approach it like you are doing it right now.
The MERGE statement merges two tables - the two tables you define in the header - the source table and the target table.
Right now, you're using tblOrders as your source, and tblProducts as your target. That alone seems odd - you're trying to merge orders into products? Doesn't seem very fitting...
Once you've defined your source and target table - you stat comparing which rows from the source are present in the target (or not). If a given row from your source is not present in the target - then you can insert its values into the target table.
But that only works for direct column values from the source table! You cannot go out and do subqueries into other tables as you're trying to do!
So I believe what you really should do is this:
as your source - have a view that lists the products found in your orders - the products (not the orders per se)
then compare your Products table to this view - if your orders happen to have any products that aren't present in the base Products table - insert them.
So you'd need something like:
MERGE tblProductsSold AS Target
USING (SELECT tblItemsOnOrder.txtOrderID, tblOrders.txtDateTime,
tblItemsOnOrder.txtPartNO, tblItemsOnOrder.txtQty
FROM tblOrders
INNER JOIN tblItemsOnOrder ON tblOrders.OrderID = tblItemsOnOrder.txtOrderID
WHERE tblOrders.txtIsConfirmed = '1') AS Source
ON Source.OrderID = Target.txtOrderID
WHEN NOT MATCHED THEN
INSERT (txtOrderID, txtOrderdate, txtPartno, txtQty)
VALUES (Source.OrderID, Source.txtDateTime, Source.txtPartNo, Source.txtQty)
OUTPUT $action ;