Execute result from subquery in a merge into statement - sql

I have a query that has as the output the following table (2 columns). What it means, is that I'm going to use the result to wrap it inside a merge into statement.
INSERT_COLUMNS UPDATE_COLUMNS
BANK_NAME target.BANK_NAME = source.BANKNAME
What I'm talking about is this:
with sql_prepare_merge as (
SELECT *
FROM another_table
),
MERGE INTO bank_raw AS target
USING bank AS source
ON source.id = target.id
WHEN MATCHED THEN
UPDATE SET (select update_columns from sql_prepare_merge)
WHEN NOT MATCHED THEN
INSERT (select insert_columns from sql_prepare_merge)
VALUES (source.id, (select insert_columns from sql_prepare_merge));
Keep in mind that the "sql_prepare_merge" is the name from the CTE where I'm getting the table I shared with you - and it has much more code in it, but they don't help here. So, I'm planning to take the text resulting from the subquery and insert it inside the merge statement.
So far, the error I'm getting is: syntax error line 19 at position 4 unexpected 'WHEN'.. By the way, this is inside Snowflake.

Unfortunately this is not possible as per my understanding of the docs: https://docs.snowflake.com/en/sql-reference/sql/merge.html#notmatchedclause-for-inserts
In the non matched clause for inserts you can specify only such values/expressions, refer to the source relations. This means you somehow need to adjust your source part itself (e.g. by joining the initial source with another_table). If this is not possible, you would need to go for separate INSERT and UPDATE statements.

Related

Why does my code not merge table 1 to the bottom of table 2?

SELECT * INTO "2020_to_2021_divvy_tripdata"
FROM
(MERGE [PortfolioDB].[dbo].['202008-divvy-tripdata$'] as "202008"
USING [PortfolioDB].[dbo].['202007-divvy-tripdata$'] as "202007" on [202007].ride_id = [202008].ride_id
WHEN NOT MATCHED THEN
INSERT VALUES ([202008].*)
I want it to take the data from 202008 and merge it to 202007 so that the one table simply is merged to the bottom of the other, but it says Incorrect syntax near *. I have tried all my previous toolkits like changing square brackets combinations and such.
Both tables are formatted the same, with the column names matching.
I tried to emulate the code from here. Eventually, I will merge multiple months onto each other to create a full-year table.
Your INSERT VALUES() has two issues...
You should insert from [202007] (the source), not from [202008] (the destination)
You can't use [202007].*, you have to list all the columns individually
Then, you need an OUTPUT clause for the MERGE to make its data available to an outer query.
Here's a demo: db<>fiddle
Here's a potential re-write of your statement...
INSERT INTO
"2020_to_2021_divvy_tripdata"
SELECT
*
FROM
(
MERGE [PortfolioDB].[dbo].['202008-divvy-tripdata$'] as "202008"
USING [PortfolioDB].[dbo].['202007-divvy-tripdata$'] as "202007"
ON [202007].ride_id = [202008].ride_id
WHEN NOT MATCHED THEN
INSERT VALUES ([202007].x, [202007].y, [202007].z)
OUTPUT
inserted.*
)
merge_inserted

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.

SQL Server MERGE with Insert subquery

I'm having trouble getting this compound insert to work in my MERGE statement between two tables (Ignore the when match condition, I know its bad practice). The issue I'm having is getting the ServerId field in the target table to fill. The Team field is filling fine but all of the rows have a null value for ServerId. I can't find an example online for this so I'm hoping someone can help. I don't seem to have any syntactical errors and I know the column 'ServerName' in the Source table is filled for all rows.
MERGE ApplicationTeams AS Target
USING TempApplicationTeams AS Source
ON (Target.ServerId = (SELECT ID from Servers WHERE Name='Source.ServerName') AND Target.Team = Source.Team)
WHEN MATCHED THEN
UPDATE SET Target.Team = Target.Team
WHEN NOT MATCHED BY TARGET THEN
INSERT (ServerId, Team) VALUES((SELECT ID from Servers WHERE Name='Source.ServerName'), Source.Team)
WHEN NOT MATCHED BY SOURCE THEN
DELETE
;
Thanks.
I think you should remove the single quoutes on the where clausule.
You wrote:
(SELECT ID from Servers WHERE Name='Source.ServerName')
But I think you should write this:
(SELECT ID from Servers WHERE Name=Source.ServerName)
And make sure the select id returns only one row otherwise the statement will fail
I hope it will be usefully

Synchronizing 2 tables with MERGE

I’ve been tasked to synchronize 2 tables (both are identical). They have 60 columns each. Table A is the primary table that will be initially filled. I need to create a stored procedure (done) that will merge these 2 tables and populate both with the same exact data (Update, insert, delete) when called. How would I use the MERGE function in SQL to achieve this? I’ve looked at both the MSDN documentation and similar that’s on technet, but I’m pretty confused on getting started. Do I need to specify each field I need merged? Or is it a simple call I’m missing that will perform this action?
Here is a link to a simple example of the MERGE statement:
http://www.simple-talk.com/sql/learn-sql-server/the-merge-statement-in-sql-server-2008/
The basic syntax reads as:
MERGE table1
USING table2
ON table1.id = table2.id
WHEN MATCHED THEN
--Do an update here
WHEN NOT MATCHED BY TARGET THEN
--Do an insert here (or a delete)
;
You can also use WHEN NOT MATCHED BY SOURCE
Over 60 columns is a great number! When I need to sync 2 identical table I do:
;WITH tbl_to_synch as (
-- Prepare table to update,
Select *,chk = CHECKSUM(*) from [dbo].[tableA]
)
MERGE tbl_to_synch as [Target]
USING (Select *,chk = CHECKSUM(*) from [dbo].[tableB]) as [source]
ON [Target].key = [source].key
WHEN MATCHED AND [Target].chk <> [source].chk THEN
-- UPDATE ONLY row that is changed
UPDATE
SET
column01 = [source].[column01]
,column02 = [source].[column01]
-- ....
,column59 = [source].[column59]
,column60 = [source].[column59]
WHEN NOT MATCHED BY TARGET THEN
insert (column01, column02, ...,column59,column60)
values (column01, column02, ...,column59,column60)
WHEN NOT MATCHED BY SOURCE THEN DELETE
-- Show what is changed
OUTPUT $action, ISNULL(INSERTED.key,DELETED.key);

Update with except statement

This is my query
SELECT PageVisit_ID,TargetSite_ID FROM [A].Datawarehouse.mi.ctb_PageEvent WITH (NOLOCK)
EXCEPT
SELECT PageVisit_ID ,TargetSite_ID FROM [B].Datawarehouse.mi.ctb_PageEvent WITH (NOLOCK)
these two tables from two servers. I need to update targetsite_id in [A].Datawarehouse.mi.ctb_PageEvent records from [B].Datawarehouse.mi.ctb_PageEvent
only matched with above query results.
Try this
DECLARE #SummaryOfChanges TABLE(Change VARCHAR(20));
MERGE INTO [A].Datawarehouse.mi.ctb_PageEvent AS Target
USING ( SELECT PageVisit_ID ,TargetSite_ID FROM [B].Datawarehouse.mi.ctb_PageEvent WITH (NOLOCK)) AS SOURCE
ON Target.TargetSite_ID = Source.TargetSite_ID
WHEN MATCHED THEN
//UPDATE OR do nothing
WHEN NOT MATCHED BY TARGET THEN
//INSERT
OUTPUT $action INTO #SummaryOfChanges;
Please refer to SQL SERVER – Merge Operations – Insert, Update, Delete in Single Execution. my solution just gives a basic idea on how to do this. It might not work 100% initially. Just tweak it once you understand the logic