How to use MERGE or Upsert Sql statement - sql

How can i use MERGE Sql Statement or UPDATE statement for my below code. I am having a columnName called MachineName, other column values change but MachineName doesnot change. If the Column MachineName changes i need to insert the new values in a secondrow. If not i need to Update the same row. How can i do this. Is it a right approach ? Please help
MERGE INTO [devLaserViso].[dbo].[Machine] WITH (HOLDLOCK)
USING [devLaserViso].[dbo].[Machine]
ON (MachineName = MachineName)
WHEN MATCHED
THEN UPDATE SET MachineName = L1,ProgramName= ancdh.pgm, TotalCount= 10, RightCount=4,
LeftCount= 3,ErrorCode=0,FinishingTime=fsefsefef
WHEN NOT MATCHED
THEN INSERT (MachineName, ProgramName, TotalCount, RightCount, LeftCount, ErrorCode, FinishingTime)
VALUES (L02, djiwdn.pgm, 11, 5, 4, 0, dnwdnwoin);

I've had success in the past "Selecting" the values to upsert into the USING section of the MERGE command:
MERGE INTO [devLaserViso].[dbo].[Machine] WITH (HOLDLOCK) AS Target
USING (SELECT 'L1' AS MachineName, 'ancdh.pgm' AS ProgramName, 10 AS TotalCount,
4 AS RightCount, 3 AS LeftCount, 0 AS ErrorCode, 'fsefsefef' AS FinishingTime) AS Source
ON (Target.MachineName = Source.MachineName)
WHEN MATCHED
THEN UPDATE SET ProgramName= Source.ProgramName, TotalCount= Source.TotalCount,
RightCount= Source.RightCount, LeftCount= Source.LeftCount,
ErrorCode= Source.ErrorCode, FinishingTime= Source.FinishingTime
WHEN NOT MATCHED
THEN INSERT (MachineName, ProgramName, TotalCount, RightCount, LeftCount, ErrorCode, FinishingTime)
VALUES (Source.MachineName, Source.ProgramName, Source.TotalCount, Source.RightCount,
Source.LeftCount, Source.ErrorCode, Source.FinishingTime);

You can load the new Machine data in a Temporary table and then can use the Merge statement as follows to update the records for which there is already a record in Machine table and will insert a new record if it does not exists in Machine table.
MERGE [devLaserViso].[dbo].[Machine] t WITH (HOLDLOCK)
USING [devLaserViso].[dbo].[TempMachine] s
ON (s.MachineName = t.MachineName)
WHEN MATCHED THEN
UPDATE SET t.MachineName = s.MachineName,t.ProgramName =s.ProgramName
WHEN NOT MATCHED BY TARGET THEN INSERT (MachineName,ProgramName) VALUES (s.MachineName, s.ProgramName);

Related

The following query use for check duplicate data in table then update or insert row

I have the following query use for check duplicate data in table. If match data then update row else insert new row. In my case I have already one matched row in att_log table where emp_id=19.1.0121 and where mp_pk_id='32' AND att_date='2021-10-01', so result should be SET holiday=H in the matched row. But the DECLARE statement run without error and in console show affected row:1, but no change occur in data base, holiday not set to "H".
DECLARE c_emp_id att_log.emp_id%type;
BEGIN
SELECT emp_id
INTO c_emp_id
FROM att_log
WHERE emp_id='19.1.0121'
AND emp_pk_id='32'
AND att_date='2021-10-01' ;
EXCEPTION
WHEN TOO_MANY_ROWS THEN
UPDATE att_log
SET holiday = 'H',
updated_at = '2021-08-22'
WHERE emp_id='19.1.0121'
AND att_date='2021-10-01';
WHEN NO_DATA_FOUND THEN
INSERT INTO att_log (emp_id, emp_pk_id, att_date, holiday,login_time, logout_time)
VALUES ('19.1.0121', '32', '2021-10-01','H','','');
COMMIT WORK;
END;
If I run the query separately without DECLARE statement then data row change happen, but with the above DECLARE statement no change happen in data row in the ORACLE table. What is my fault! Sorry, I am new to ORACLE, and also sorry for poor English.
A MERGE operation can INSERT or UPDATE (and also DELETE) depending on whether the row exists or not.
Here's a working test case:
Test case / fiddle
Example of MERGE:
CREATE TABLE logs (
id NUMBER GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL
, text VARCHAR2(20) UNIQUE
, q int DEFAULT 1
);
INSERT INTO logs (text) VALUES ('A');
INSERT INTO logs (text) VALUES ('B');
INSERT INTO logs (text) VALUES ('C');
MERGE INTO logs USING (SELECT 'B' AS text FROM dual) cte ON (cte.text = logs.text)
WHEN MATCHED THEN UPDATE SET logs.q = logs.q + 1
WHEN NOT MATCHED THEN INSERT (logs.text)
VALUES (cte.text)
;
Result:
and now we can do this for several existing rows and new rows at once:
MERGE INTO logs USING (
SELECT text FROM logs WHERE text > 'A' UNION
SELECT 'Z' FROM dual
) cte ON (cte.text = logs.text)
WHEN MATCHED THEN UPDATE SET logs.q = logs.q + 1
WHEN NOT MATCHED THEN INSERT (logs.text)
VALUES (cte.text)
;
New Result:
This example will either INSERT a new row when the rows in cte do not exist in logs, and UPDATE any existing rows in logs when matches are found, by incrementing q.

Bug in SQL Server MERGE statement

I am trying to write a MERGE statement. If the record exists, update it. If it doesn't exist, insert it.
This query runs, but is says '0 rows affected'. I know that an add_id of '3' does not exist, so I would expect it to insert a row. What am I doing wrong? Sorry, I've never written a merge query before.
MERGE INTO dbo.delay AS TARGET
USING (SELECT * FROM dbo.delay WHERE add_id = 3) AS SOURCE ON (Source.add_id = Target.add_id)
WHEN MATCHED
THEN UPDATE SET my_value = 22
WHEN NOT MATCHED BY TARGET
THEN INSERT (add_id, my_value) VALUES (1, 22);

MERGE statement DELETE alternative in SQL Server

I have a Query using T-SQL MERGE Statement. Due to performance issues I am re writing the Query using IF Exists Update and If Not Exists Insert. I am able to write Insert/Update without any issue. But I am unable to handle the DELETE. Can some one please help me on this?
Here is the sample
---SAMPLE MERGE STATEMENT
MERGE
member_topic AS target
USING
someOtherTable AS source
ON
target.mt_member = source.mt_member
WHEN MATCHED THEN
UPDATE SET target.mt_notes = source.mt_notes
WHEN NOT MATCHED THEN
INSERT (mt_member, mt_topic, mt_notes) VALUES (source.mt_member, source.mt_notes)
WHEN NOT MATCHED BY SOURCE THEN
DELETE member_topic;
--UPDATE
UPDATE T SET T.mt_notes = S.mt_notes
FROM member_topic T
JOIN someOtherTable S ON T.mt_member=S.mt_member
--INSERT
INSERT INTO member_topic(mt_member, mt_topic, mt_notes)
SELECT mt_member, mt_topic, mt_notes
FROM someOtherTable S
WHERE NOT EXISTS(SELECT 1
FROM member_topic T
WHERE T.mt_member=S.mt_member)
How to handle
WHEN NOT MATCHED BY SOURCE THEN
DELETE member_topic;
in single DELETE Statement.
a sample script to be embedded between begin and end in proc
MERGE dbo.Tablet AS TARGET
USING dbo.QueryView AS SOURCE
ON (
TARGET.[ID] = SOURCE.[ID]
)
WHEN MATCHED
THEN
UPDATE SET
TARGET.[ID] = SOURCE.[ID]
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, [Name] )
VALUES (SOURCE.[ID], SOURCE.[Name] )
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
Try
DELETE T
FROM member_topic T
WHERE NOT EXISTS(SELECT 1
FROM someOtherTable S
WHERE T.mt_member=S.mt_member)
DELETE t
FROM member_topic t
LEFT JOIN someOtherTable s ON t.mt_member = s.mt_member
WHERE s.mt_member IS NULL

SQL Server : use a transaction in the then clause of merge

In a merge statement, when not matched, I need to insert into target table and update another table. How can I achieve this?
merge table1 as TARGET
using table2 as SOURCE ON <conditions>
when not matched by target
then
/*--------can i do this?---------*/
BEGIN TRANSACTION
insert (columnnames) values(v1,..., vn) /*insert into target*/
update source
set column1 = value1 /*update source*/
END TRANSACTION;
The whole merge statement is atomic (either the whole statement completes or the whole statement gets rolled back) so that you don't need to create a transaction.
Here's an example from Microsoft:
MERGE Production.UnitMeasure AS target
USING (SELECT #UnitMeasureCode, #Name) AS source (UnitMeasureCode, Name)
ON (target.UnitMeasureCode = source.UnitMeasureCode)
WHEN MATCHED THEN
UPDATE SET Name = source.Name
WHEN NOT MATCHED THEN
INSERT (UnitMeasureCode, Name)
VALUES (source.UnitMeasureCode, source.Name)
OUTPUT deleted.*, $action, inserted.* INTO #MyTempTable;

Having MERGE INTO do 2 things when Not Matched?

I am using the MERGE INTO statement to work with some tables, and I've a simple question. How can I make a Matched/Not Matched Statement do 2 things? For example, I have this and it works:
MERGE INTO VMFG.dbo._AR_Mill1ActiveSchedule t --target
USING #temp --source
On t.Base_ID = #temp.WORKORDER_BASE_ID AND t.Lot_ID = #temp.WORKORDER_Lot_ID
WHEN MATCHED AND #temp.rollstatus = 'R' THEN
UPDATE
SET t.sawStatus = #temp.sawstatus, t.rollStatus = #temp.rollstatus
WHEN NOT MATCHED BY TARGET THEN
INSERT (BASE_ID, LOT_ID, sawStatus, rollstatus, preheatcheck) VALUES (#temp.WorkOrder_Base_ID, #temp.WorkOrder_Lot_ID, #temp.sawStatus, #temp.rollStatus, 'False')
WHEN NOT MATCHED BY SOURCE AND t.SawStatus = 'C' THEN
Delete ;
Drop Table #temp
Now, I want to accomplish something like this:
MERGE INTO VMFG.dbo._AR_Mill1ActiveSchedule t --target
USING #temp --source
On t.Base_ID = #temp.WORKORDER_BASE_ID AND t.Lot_ID = #temp.WORKORDER_Lot_ID
WHEN MATCHED AND #temp.rollstatus = 'R' THEN
UPDATE
SET t.sawStatus = #temp.sawstatus, t.rollStatus = #temp.rollstatus
WHEN NOT MATCHED BY TARGET THEN
INSERT (BASE_ID, LOT_ID, sawStatus, rollstatus, preheatcheck) VALUES (#temp.WorkOrder_Base_ID, #temp.WorkOrder_Lot_ID, #temp.sawStatus, #temp.rollStatus, 'False')
WHEN NOT MATCHED BY SOURCE AND t.SawStatus = 'C' THEN
INSERT INTO _AR_Mill1RemovedWO (BASE_ID, LOT_ID) VALUES (#temp.WorkOrder_Base_ID, #temp.WorkOrder_Lot_ID)
Delete ;
Drop Table #temp
However, when I run this I get the error "Incorrect syntax near the keyword 'INTO'".
I've tried using the OUTPUT clause but I couldn't get it to work correctly, and would rather use an insert statement anyways if possible.
Thank you :)
EDIT:
The Output clause would be awesome to use, but I'll explain why it hasn't worked. When I used it, i.e.:
....
WHEN NOT MATCHED BY SOURCE AND t.SawStatus = 'C' THEN
--INSERT INTO _AR_Mill1RemovedWO (BASE_ID, LOT_ID) VALUES (#temp.WorkOrder_Base_ID, #temp.WorkOrder_Lot_ID)
Delete
OUTPUT deleted.Base_ID, deleted.Lot_ID INTO VMFG.dbo._AR_Mill1RemovedWO
;
Drop Table #temp
I run in to a problem. It adds rows to my table that weren't actually deleted. It's like it's just adding everything, regardless of being deleted. Is there a reason for this?
This is impossible to do with a single MERGE statement. Use the OUTPUT clause to direct information about the writes executed into a table variable. Execute a second statement such as INSERT to write to the second table.