Merge SQL With Condition - sql

I have a Scenario where i need to User Merge SQL statement to Synchronize two Tables. Let's suppose i have two tables Table A and Table B. Schema is same with the exception of one Extra Column in Table A. That Extra column is a flag that tells me which records are ready to be inserted/updated in Table B. Lets say that flag column is IsReady. It will be either true or False.
Can i use Isready=True in Merge Statement or I need a Temp table to move all records from Table A to Temp Table where IsReady=True and then use Merge SQL on TempTable and Table B???

Yes, you can use that column in the merge condition.
merge tableB targetTable
using tableA sourceTable
on sourceTable.IsReady = 1 and [any other condition]
when not matched then
insert ...
when matched and [...] then
update ...

This may help you,
merge into tableB
using tableA
on tableB.IsReady=true
when not matched then
insert (tableB.field1,tableB.field2..)
values (tableA.field1,tableA.field2..);
commit;

Related

Insert into select, target data unaffected

We have a simple query
INSERT INTO table2
SELECT *
FROM table1
WHERE condition;
I can read somewhere that to use INSERT INTO SELECT statement, the following condition must be fulfilled:
The existing records in the target table are unaffected
What does it mean?
INSERT is a SQL operations that add some new rows into your table, with not affect on the others. This is happening instead of UPDATE operations, that cand affect multiple rows from your table if you use a wrong WHERE Clause.

Push deleted items into temporary table after MERGE

A simple query on the INTO clause. When i try the below statement, the items get pushed into CustomersBackup2013 whether the table exists or not.
SELECT *
INTO CustomersBackup2013
FROM Customers;
However, when i try using the into clause in a MERGE like
MERGE TargetTable tt
USING SyncTable st on <condition>
.
.
WHEN Not MATCHED BY SOURCE
DELETE
OUTPUT deleted.* INTO #Sometemptable;
I get an error saying invalid object name '#Sometemptable'
Isnt it supposed to create the table if it does not exist? Is there something I am doing wrong.
Is there any way i can modify the clause to push items into #Sometemptable?
No, the table has to exists for the output clause to work.
First create the #temp table and then you can output deleted values in it. Columns in the temp table must match columns from output by ordinal and type.
select into table creates a table if required. it is much like oracle's create table as select. see here select into table
merge only inserts, updates or deletes

Filtering duplicate records while importing data from source table to target table

This may be a simple query to some of you. But I am not strong in Sql, so expecting some solution for my problem.
I have 2 tables, ProductVenueImport and SupplierVenueImport.
We are dumping all the records from SupplierVenueImport to ProductVenueImport using MERGE clause and a Temp table. Temp will have valid records from SupplerVenuImport and from Temp table we are importing records to ProductVenueImport.
But before importing data to ProductVenueImport from Temp table I need to check for the duplicate records in my target (ProductVenueImport).
For example if I am importing a record with name as 'A', I need to look into ProductVenueImport whether 'A' already existing or not. If it is not existing then only I need to insert 'A' otherwise not.
Could somebody tell me how to do this?
Is using Cursors only the option?
Thanks,
Naresh
Assuming the Temp table itself doesn't have duplicates, you could use MERGE like this:
Insert non-existing products.
Do a NO-OP in case of an existing product.
Use $action in the OUTPUT clause to mark which rows were considered for insertion (and inserted) and which for update (but not really updated).
This is what I mean:
DECLARE #noop int; -- needed for the NO-OP below
MERGE INTO ProductVenueImport AS tgt
USING Temp AS src
ON src.ProductID = tgt.ProdutID
WHEN NOT MATCHED THEN
INSERT ( column1, column2, ...)
VALUES (src.column1, src.column2, ...)
WHEN MATCHED THEN
UPDATE SET #noop = #noop -- the NO-OP instead of update
OUTPUT $action, src.column1, src.column2, ...
INTO anotherTempTable
;
I think this would do this :
INSERT INTO PRODUCTTBL(FEILD1, FIELD2, FIELD3, FIELD4, FIELD5)
SELECT (FIELD1,FIELD2,FIELD3,FIELD4,FIELD5) FROM TEMP WHERE CRITERIAFIELD NOT IN(SELECT DISTINCT CRITERIAFIELD FROM PRODUCTTBL)
This should allow you to check for duplicates in a table
select columnname from tablename
group by columnname
having count(columnname) >1
sorry if I am not getting the question right, can't you use the merge statement on the source table with "When not matched Insert" to insert the new records alone
so in your case it should be like this
merge into ProductVenueImport using temp on (<condition for duplicate>)
when not matched then insert <clause>;
the merge clause will make sure that no duplicate records are inserted into your source table.

How to synchronize two tables in SSIS

I have a scenario where i need to synchronize two tables in SSIS
Table A is in DATABASE A and TABLE B is in DATABASE B. Both tables have same schema. I need to have a SSIS package that Synchronize TABLE A with TABLE B in Such a way That
1. It inserts all the records That Exist in Table A into Table B
AND
2. Update TABLE B if Same "Key" exsit in Both but Updated records in Table A
For Example Table A and B both Contains Key = 123 both Few Columns in Table A has been Updated.
I am thinking about using Merge Joins but that helps with only insertion of New records. How i can manage to implement UPDATE thing as well
1.It inserts all the records That Exist in Table A into Table B
Use a lookup transformation .Source will be Table A and Lookup will be Table B .Map the common columns in both the table and select those columns which you need for insertion.After lookup use OLEDB destination and the map the columns coming from the lookup and insert it into Table B
2.Update TABLE B if Same "Key" exsit in Both but Updated records in Table A
Same logic as above .Use lookup and instead of OLEDB Destination use OLEDB Command and then write the update sql .
Update TableB
Set col1=?,col2=?....
In the column mapping map the columns coming out of the lookup
Check out this article
Checking to see if a record exists and if so update else insert
Using Merge :
MERGE TableB b
USING TableA a
ON b.Key = a.Key
WHEN MATCHED AND b.Col1<>a.Col1 THEN
UPDATE
SET b.Col1 = a.Col1
WHEN NOT MATCHED BY TARGET THEN
INSERT (Col1, Col2, col3)
VALUES (a.Col1, a.Col2,a.Col3);
You can execute the Merge SQL in Execute SQL Task in Control Flow
Update : The Lookup transformation tries to perform an equi-join between values in the transformation input and values in the reference dataset.
You can just need to have one Data Flow Task .
Diagram
When the target table data does not have a matching value in the source table then lookup will redirect the target rows to the oledb destination which inserts the Data into source table( Lookup No Match Output)
When the target table rows matches for the business key with the source table then matched rows will be sent to the Oledb Command and using the Update SQL ,the all the target rows from the lookup will be updated in the source table .
This is just an overview .There is a problem with the above design as when the rows matches irrespective of any change in the columns the source table will be updated .So kindly refer the above article or try for search for SCD component in ssis
Update 2:
MERGE TableB b
USING TableA a
ON b.Key = a.Key
WHEN MATCHED THEN
UPDATE
SET b.Col1 = a.Col1
WHEN NOT MATCHED BY TARGET AND a.IsReady=1 THEN --isReady bit data type
INSERT (Col1, Col2, col3)
VALUES (a.Col1, a.Col2,a.Col3);

How to fix this stored procedure problem

I have 2 tables. The following are just a stripped down version of these tables.
TableA
Id <pk> incrementing
Name varchar(50)
TableB
TableAId <pk> non incrementing
Name varchar(50)
Now these tables have a relationship to each other.
Scenario
User 1 comes to my site and does some actions(in this case adds rows to Table A). So I use a SqlBulkCopy all this data in Table A.
However I need to add the data also to Table B but I don't know the newly created Id's from Table A as SQLBulkCopy won't return these.
So I am thinking of having a stored procedure that finds all the id's that don't exist in Table B and then insert them in.
INSERT INTO TableB (TableAId , Name)
SELECT Id,Name FROM TableA as tableA
WHERE not exists( ...)
However this comes with a problem. A user at any time can delete something from TableB so if a user deletes say a row and then another user comes around or even the same user comes around and does something to Table A my stored procedure will bring back that deleted row in Table B. Since it will still exist in Table A but not Table B and thus satisfy the stored procedure condition.
So is there a better way of dealing with two tables that need to be updated when using bulk insert?
SQLBulkCopy complicates this so I'd consider using a staging table and an OUTPUT clause
Example, in a mixture of client pseudo code and SQL
create SQLConnection
Create #temptable
Bulkcopy to #temptable
Call proc on same SQLConnection
proc:
INSERT tableA (..)
OUTPUT INSERTED.key, .. INTO TableB
SELECT .. FROM #temptable
close connection
Notes:
temptable will be local to the connection and be isolated
the writes to A and B will be atomic
overlapping or later writes don't care about what happens later to A and B
emphasising the last point, A and B will only ever be populated from the set of rows in #temptable
Alternative:
Add another column to A and B called sessionid and use that to identify row batches.
One option would be to use SQL Servers output clause:
INSERT YourTable (name)
OUTPUT INSERTED.*
VALUES ('NewName')
This will return the id, name of the inserted rows to the client, so you can use them in the insert operation for the second table.
Just as an alternative solution you could use database triggers to update the second table.