Table: Employee
EmployeeID |
FirstName |
LastName |
Title |
HireDate |
ManagerID |
1 |
George |
Cruz |
CEO |
12/8/2008 |
NULL |
2 |
John |
Mathew |
Vice President |
4/1/2009 |
1 |
3 |
Ethan |
William |
Director I |
8/8/2009 |
2 |
4 |
Jacob |
Logan |
Director II |
12/8/2011 |
3 |
5 |
Nathan |
Mateo |
Senior Manager |
9/3/2009 |
4 |
6 |
Alice |
Charles |
Manager I |
12/8/2012 |
5 |
7 |
John |
Robert |
Manager II |
10/8/2011 |
6 |
8 |
Sophia |
James |
Manager III |
5/8/2011 |
7 |
9 |
Kevin |
Chan |
Product Manager |
7/8/2011 |
5 |
10 |
Susan |
Mortiz |
Solutions Arthitect |
1/3/2012 |
6 |
11 |
Martha |
Miller |
Systems Arthitect |
12/15/2012 |
10 |
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
12/8/2008 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Manager I |
8/8/2009 |
New York |
1 |
8/8/2009 |
4 |
Jacob Logan |
Manager II |
12/8/2011 |
New York |
1 |
12/8/2011 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
1 |
10/1/2010 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
1 |
5/25/2013 |
Following are the changes which needs to be done.
-
Position column for two employees (EmployeeID 3 and 4) has been updated in the Employee table. These need to be updated in the EmployeeArchive table.
-
Employee table has two new employees (EmployeeID 7 and 8). These employees needs to be inserted into the EmployeeArchive table.
-
EmployeeArchive table has two employees (EmployeeID 5 and 6) who have been removed from the Employee table. This means that the Active column in the EmplyeeArchive table needs to be updated to 0.
Let’s break down all the requirements into smaller tasks.
First let’s find employees who are common to both the tables and make updates to EmployeeArchive table with data from the Employee table.
This will take care of the first requirement by updating the Position column in the EmployeeArchive table for EmployeeID 3 and 4.
Query 1:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN MATCHED THEN
UPDATE
SET EA.Name = E.Name,
EA.Position = E.Position,
EA.HireDate = E.HireDate,
EA.Location = E.Location,
EA.Active = 1,
EA.LastUpdated = GETDATE();
In the above query, the MERGE keyword is followed by an optional INTO keyword, name of the target table and an alias for the target table.
In this case EmployeeArchive is the target table, and all the operations will be performed on this table.
After defining the target table, the next line defines the source table. In this case, Employee is the source table which will be matched with the target table.
The condition of match is defined in the next line after the ON keyword. In this case, the condition is that EmployeeID in the target table should match the EmployeeID in the source table.
After defining both the target and the source tables, the query defines the WHEN MATCHED clause.
If you look at the original table, there are four rows (EmployeeID 1, 2, 3, 4) in the target table which matches with the source table.
The operations performed within the WHEN MATCHED clause will only affect these four rows. In the query, WHEN MATCHED clause includes an UPDATE action which updates all the columns in the EmployeeArchive table.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
11/23/2024 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
11/23/2024 |
3 |
Ethan William |
Director I |
8/8/2009 |
New York |
1 |
11/23/2024 |
4 |
Jacob Logan |
Director II |
12/8/2011 |
New York |
1 |
11/23/2024 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
1 |
10/1/2010 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
1 |
5/25/2013 |
From the output, you can see that the position column for EmployeeID 3 and 4 has been updated to the most recent position.
You will also notice that LastUpdated column for all the matched rows has been updated including rows for EmployeeID 1 and 2 which did not require any updates.
To fix this, we should add condition in the WHEN MATCHED clause so that only the rows which require updates need to be updated.
Query 2:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN MATCHED AND
(EA.Name <> E.Name OR
EA.Position <> E.Position OR
EA.HireDate <> E.HireDate OR
EA.Location <> E.Location OR
EA.Active = 0) THEN
UPDATE
SET EA.Name = E.Name,
EA.Position = E.Position,
EA.HireDate = E.HireDate,
EA.Location = E.Location,
EA.Active = 1,
EA.LastUpdated = GETDATE();
The above query adds condition in the WHEN MATCHED clause so that UPDATE operation is performed for only those matched rows where the column values in the target table
differs from the column values in the source table.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
12/8/2008 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Director I |
8/8/2009 |
New York |
1 |
11/23/2024 |
4 |
Jacob Logan |
Director II |
12/8/2011 |
New York |
1 |
11/23/2024 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
1 |
10/1/2010 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
1 |
5/25/2013 |
From the output, you can see that LastUpdated date has been changed for only those rows where the data is different from the Employee table.
In this case, only rows with EmployeeID 3 and 4 were updated.
Rows with EmployeeID 1 and 2 were not updated because none of the values in the EmployeeArchive table differs from values in the Employee table.
It is possible in a MERGE statement to have two WHEN MATCHED clauses.
When two WHEN MATCHED clauses are used, one of them must perform an UPDATE action and the other one must perform a DELETE action, also the first clause must include an AND operator.
The following query is just for explanation purposes since this is not part of the requirement.
Query 3:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN MATCHED AND
EA.HireDate < '2009-01-01' THEN
DELETE
WHEN MATCHED AND
(EA.Name <> E.Name OR
EA.Position <> E.Position OR
EA.HireDate <> E.HireDate OR
EA.Location <> E.Location OR
EA.Active = 0) THEN
UPDATE
SET EA.Name = E.Name,
EA.Position = E.Position,
EA.HireDate = E.HireDate,
EA.Location = E.Location,
EA.Active = 1,
EA.LastUpdated = GETDATE();
The above query uses two WHEN MATCHED clauses. The first one checks whether the value in the HireDate column in the EmployeeArchive table is less than 01/01/2009.
If it is, then the row is deleted from the EmployeeArchive table.
The second WHEN MATCHED clause does an update on EmployeeArchive table if there exists any difference in column values between EmployeeArchive table and Employee table.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Director I |
8/8/2009 |
New York |
1 |
11/23/2024 |
4 |
Jacob Logan |
Director II |
12/8/2011 |
New York |
1 |
11/23/2024 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
1 |
10/1/2010 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
1 |
5/25/2013 |
To achieve the second requirement, we need to insert new employees (EmployeeID 7 and 8) from Employee table to EmployeeArchive table.
For this, we would need to make use of WHEN NOT MATCHED BY TARGET clause. This clause checks for rows which are present in the source table but are missing in the target table.
Query 4:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN NOT MATCHED BY TARGET THEN
INSERT(EmployeeID, Name, Position, HireDate, Location, Active, LastUpdated)
VALUES(E.EmployeeID, E.Name, E.Position, E.HireDate, E.Location, 1, GETDATE());
The above query makes use of the WHEN NOT MATCHED BY TARGET clause to extract the rows which are present in the Employee table but not in EmployeeArchive table.
In the query, WHEN NOT MATCHED BY TARGET keywords are followed by an INSERT statement which inserts the extracted rows from the Employee table into EmployeeArchive table.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
12/8/2008 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Manager I |
8/8/2009 |
New York |
1 |
8/8/2009 |
4 |
Jacob Logan |
Manager II |
12/8/2011 |
New York |
1 |
12/8/2011 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
1 |
10/1/2010 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
1 |
5/25/2013 |
7 |
Nathan Mateo |
Senior Manager |
3/6/2013 |
San Francisco |
1 |
11/23/2024 |
8 |
Alice Charles |
Manager I |
6/14/2013 |
San Francisco |
1 |
11/23/2024 |
As you can see in the output, new rows from source table has been inserted into the target table. In this case, EmployeeID 7 and 8 were inserted into EmployeeArchive table.
The final requirement is that, Active column for rows in the EmployeeArchive table which does not exist in the Employee table needs to be updated to 0.
That means Active column for rows with EmployeeID 5 and 6 in the EmployeeArchive table needs to be updated to 0.
To do this, we need to make use of WHEN NOT MATCHED BY SOURCE clause. This clause checks for rows which are present in the target table but not in the source table.
Query 5:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN NOT MATCHED BY SOURCE THEN
UPDATE
SET EA.Active = 0,
EA.LastUpdated = GETDATE();
In the above query, WHEN NOT MATCHED BY SOURCE clause extracts rows from the target table which are not present in the source table.
In this case, rows with EmployeeID 5 and 6 in the EmployeeArchive table.
Notice that WHEN NOT MATCHED BY SOURCE keywords are followed by an UPDATE statement which updates the extracted rows and sets the Active column to False and LastUpdate column to the current date.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
12/8/2008 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Manager I |
8/8/2009 |
New York |
1 |
8/8/2009 |
4 |
Jacob Logan |
Manager II |
12/8/2011 |
New York |
1 |
12/8/2011 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
0 |
11/23/2024 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
0 |
11/23/2024 |
Just like WHEN MATCHED clause, it is possible to have two WHEN NOT MATCHED BY SOURCE clause in a single MERGE statement.
WHEN two WHEN NOT MATCHED BY SOURCE clauses are used, then one must perform an UPDATE action and the other one must perform a DELETE action.
The following query is just for explanation purposes since this is not part of the requirement.
Query 6:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN NOT MATCHED BY SOURCE AND
EA.HireDate < '01/01/2009' THEN
DELETE
WHEN NOT MATCHED BY SOURCE THEN
UPDATE
SET EA.Active = 0,
EA.LastUpdated = GETDATE();
The above query gives an example of two WHEN NOT MATCHED BY SOURCE clause in a single MERGE statement.
Notice that out of the two clauses, the first one has a condition and performs a DELETE operation for rows in the EmployeeArchive table.
The second clause performs an UPDATE operation for rows which were not part of the DELETE operation.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
12/8/2008 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Manager I |
8/8/2009 |
New York |
1 |
8/8/2009 |
4 |
Jacob Logan |
Manager II |
12/8/2011 |
New York |
1 |
12/8/2011 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
0 |
11/23/2024 |
As you can see from the output, row with EmployeeID 5 has been deleted from the EmployeeArchive table.
This is because the HireDate column for the row had a value less 01/01/2009.
Also notice that for the row with EmployeeID 6, Active column has been updated to 0 and LastUpdated column has been updated to the current date.
Finally let’s put all the clauses together and build the final MERGE statement which will satisfy all the three requirements.
Query 7:
MERGE INTO EmployeeArchive AS EA
USING Employee AS E
ON EA.EmployeeID = E.EmployeeID
WHEN MATCHED AND
(EA.Name <> E.Name OR
EA.Position <> E.Position OR
EA.HireDate <> E.HireDate OR
EA.Location <> E.Location OR
EA.Active = 0) THEN
UPDATE
SET EA.Name = E.Name,
EA.Position = E.Position,
EA.HireDate = E.HireDate,
EA.Location = E.Location,
EA.Active = 1,
EA.LastUpdated = GETDATE()
WHEN NOT MATCHED BY TARGET THEN
INSERT(EmployeeID, Name, Position, HireDate, Location, Active, LastUpdated)
VALUES(E.EmployeeID, E.Name, E.Position, E.HireDate, E.Location, 1, GETDATE())
WHEN NOT MATCHED BY SOURCE THEN
UPDATE
SET EA.Active = 0,
EA.LastUpdated = GETDATE();
As you can see, the query includes all three WHEN MATCHED, WHEN NOT MATCHED BY TARGET and WHEN NOT MATCHED BY SOURCE clauses.
The first clause which is a WHEN MATCHED clause, checks for any changes in column values for rows with matching EmployeeID.
WHEN MATCHED clause then updates rows in the EmployeeArchive table where the column values do not match with the values in the Employee table.
The second clause which is a WHEN NOT MATCHED BY TARGET clause, checks for rows which exists in the source table but are missing in the target table.
WHEN NOT MATCHED BY TARGET clause then inserts the missing records into the EmployeeArchive table.
Finally WHEN NOT MATCHED BY SOURCE clause checks for rows in the target table which does not exist in the source table.
WHEN NOT MATCHED BY SOURCE clause then updates the target table for rows which does not exist in the source table.
Table: EmployeeArchive
EmployeeID |
Name |
Position |
HireDate |
Location |
Active |
LastUpdated |
1 |
George Cruz |
CEO |
12/8/2008 |
San Francisco |
1 |
12/8/2008 |
2 |
Steve Mathew |
Vice President |
4/1/2009 |
San Francisco |
1 |
4/1/2009 |
3 |
Ethan William |
Director I |
8/8/2009 |
New York |
1 |
11/23/2024 |
4 |
Jacob Logan |
Director II |
12/8/2011 |
New York |
1 |
11/23/2024 |
5 |
Able Andrea |
Intern |
7/15/2008 |
San Francisco |
0 |
11/23/2024 |
6 |
Best Donald |
Intern |
1/16/2013 |
San Francisco |
0 |
11/23/2024 |
7 |
Nathan Mateo |
Senior Manager |
3/6/2013 |
San Francisco |
1 |
11/23/2024 |
8 |
Alice Charles |
Manager I |
6/14/2013 |
San Francisco |
1 |
11/23/2024 |
As seen in the output, the query updated Position column for EmployeeID 3 and 4 using the WHEN MATCHED clause.
The query then inserted rows for EmployeeID 7 and 8 using WHEN NOT MATCHED BY TARGET clause.
Finally the query updated Active column for rows with EmployeeID 5 and 6 using WHEN NOT MATCHED BY SOURCE clause.