Merge insert with select statement
According to MSDN docs
<merge_not_matched>::=
{
INSERT [ ( column_list ) ]
{ VALUES ( values_list )
| DEFAULT VALUES }
}
The syntax with INSERT
from SELECT
like:
WHEN NOT MATCHED THEN
INSERT itmid SELECT itmid FROM Table3 WHERE id=@id;
Is not allowed!
I would try to solve your problem doing another merge with Table3
.
Insert Into... Merge... Select (SQL Server)
The trick is to populate the table with the MERGE
statement instead of an INSERT...SELECT
. That allowes you to use values from both inserted and source data in the output clause:
MERGE INTO Table3 USING
(
SELECT null as col2,
110 as col3,
Table1.ID as col4,
Table2.Column2 as col5,
Table2.Id as col6
FROM Table1
JOIN Table1Table2Link on Table1.ID=Table1Table2Link.Column1
JOIN Table2 on Table1Table2Link.Column2=Table2.ID
) AS s ON 1 = 0 -- Always not matched
WHEN NOT MATCHED THEN
INSERT (Column2, Column3, Column4, Column5)
VALUES (s.col2, s.col3, s.col4, s.col5)
OUTPUT Inserted.ID, s.col6
INTO @MyTableVar (insertedId, Table2Id);
How can I use insert with select from other table in a merge statement?
You wouldn't. You have already defined S
so you can reference those columns in the VALUES
clause. You also don't put the alias of the destination table prior to the destination columns:
THEN INSERT (category_id, category_name, amount)
VALUES (s.category_id, s.category_name, s.amount)
SQL MERGE - when not matched insert by using select table
Since most of your values are columns from the source table anyway - I don't see any reason why you would need a SELECT
in the INSERT
- just try this:
WHEN NOT MATCHED BY TARGET THEN
INSERT (UserID, OnProcessItem, Amount, Remarks, TranNo, IfOthers)
VALUES (@ResignEmp, b.OnProcessItem, b.Amount, b.Remarks, @TranNo, b.IfOthers);
SQL Merge Into with multiple statements
Normally you can INSERT
only into one table. The syntax does not allow multiple statements in the same "when" condition.
But, SQL Server has OUTPUT
clause which allows to add another table. It is very handy when you need to have some sort of auditing trail.
See this question How to INSERT into multiple tables from one SELECT statement
So, add OUTPUT
clause to your MERGE
statement. Something like this:
MERGE TargetProducts AS Target
USING SourceProducts AS Source
ON Source.ProductID = Target.ProductID
-- For Inserts
WHEN NOT MATCHED BY Target THEN
INSERT (ProductID,ProductName, Price)
VALUES (Source.ProductID,Source.ProductName, Source.Price)
-- For Updates
WHEN MATCHED THEN UPDATE SET
Target.ProductName = Source.ProductName,
Target.Price = Source.Price
-- For Deletes
WHEN NOT MATCHED BY Source THEN
DELETE
OUTPUT inserted.ProductID, inserted.ProductName, inserted.Price
INTO anotherTable (OldProductID,OldProductName, OldPrice)
;
This will capture both updates and inserts in anotherTable
. To capture only inserts you can output at first into a temp table and then filter results by MERGE $action
.
Have a look at this question:
Pipes and filters at DBMS-level: Splitting the MERGE output stream
Merge not inserting new values
If you look at the MERGE documentation, you will see that the source data must exist in order to match (or not match) against existing rows in the target table:
WHEN NOT MATCHED [ BY TARGET ] THEN <merge_not_matched>
Specifies that a row is inserted into target_table for every row
returned by <table_source> ON <merge_search_condition> that doesn't
match a row in target_table, but satisfies an additional search
condition, if present. The values to insert are specified by the
<merge_not_matched> clause. The MERGE statement can have only one WHEN
NOT MATCHED [ BY TARGET ] clause.
The problem you're facing is that your "source" data is not returning anything and so the MERGE query has nothing to match against or insert.
Sample code below to demo:
IF OBJECT_ID('dbo.TARGET_TABLE', 'U') IS NOT NULL DROP TABLE dbo.TARGET_TABLE
GO
CREATE TABLE TARGET_TABLE ([Name] VARCHAR(100), file_first_upload BIT, upload_date DATETIME, [STATUS] VARCHAR(100))
MERGE [dbo].[TARGET_TABLE] AS Target
USING
(SELECT [NAME]
FROM [dbo].[TARGET_TABLE]
WHERE [NAME]='ThisValuesDoesntExists' AND [STATUS] IS NULL) AS Source
ON Target.[NAME]= Source.[NAME]
WHEN NOT MATCHED
THEN INSERT ([NAME],[file_first_upload],[upload_date])
VALUES('ThisValuesDoesntExists',1,DEFAULT);
SELECT *
FROM TARGET_TABLE
MERGE [dbo].[TARGET_TABLE] AS Target
USING (VALUES ('ThisValuesDoesntExistss',1,GETDATE())) AS Source ([Name], [file_first_upload],[upload_date])
ON Target.[NAME] = Source.[Name]
WHEN NOT MATCHED
THEN INSERT ([NAME],[file_first_upload],[upload_date]) VALUES (Source.[Name], Source.file_First_upload, Source.upload_date);
SELECT *
FROM TARGET_TABLE
Related Topics
Does Anyone Use Right Outer Joins
Return a Value If No Record Is Found
Split Given String and Prepare Case Statement
Differencebetween Function and Procedure in Pl/Sql
MySQL Equivalent of Decode Function in Oracle
In SQL Server, What Does "Set Ansi_Nulls On" Mean
How to Make SQL Many-To-Many Same-Type Relationship Table
Regular Expressions in Db2 SQL
How to Get the First and Last Date of the Current Year
Dynamic SQL to Generate Column Names
Change Postgresql Columns Used in Views
Get the Last Day of the Month in SQL
How to Use Asp Variables in SQL Statement
Postgresql: Encoding Problems on Windows When Using Psql Command Line Utility
How to Delete from Multiple Tables in the Same SQL Statement
Insert Update Stored Proc on SQL Server