MERGE 与 WHERE 子句
MERGE with WHERE clause
考虑 table:
中存在的数据
客户
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyd | Killed |
| 2 | Shelby Hawthorn | Booked |
我想 MERGEd 到 Customers table:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | name has 'e' on the end
| 2 | Shelby Blanken | Waiting | different last name
| 3 | Jessica Bogden | Waiting | totally new row
所以我可以想出近似的伪代码 MERGE 语句:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
WHEN MATCHED THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
这将合并它们:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | Last name spelling updated
| 2 | Shelby Blanken | Waiting | Last name changed
| 3 | Jessica Bogden | Waiting | New row added
但只更新了一些行
除了需要注意的是,我不想为 Booked
的客户更新任何现有行。换句话说,我希望最终结果是:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | updated existing row spelling
| 2 | Shelby Hawthorn | Booked | not updated because they're booked
| 3 | Jessica Bogden | Waiting | inserted new row
我的第一个猜测是 UPDATE
有一个 where 子句:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
WHEN MATCHED THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHERE Status <> 'Booked' -- <--------- it's the matching row; but don't update it
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
但这不是有效的语法。
我的第二个猜测是将条件添加到 ON
子句:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
AND Customers.Status <> 'Booked'
WHEN MATCHED THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHERE Status <> 'Booked' --it's the matching row; but don't update it
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
但现在该行不匹配,它们将根据 not matched by target 规则插入:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | updated existing row
| 2 | Shelby Hawthorn | Booked | not matched bcause booked
| 3 | Jessica Bogden | Waiting | inserted new row
| 4 | Shelby Blanden | Waiting | Mistakenly inserted because not matched by target
走出困境的出路是什么?
合并语句由 USING 子句驱动。
- USING 中 匹配 现有行的行导致现有行更新。
- USING 中的行不匹配 现有行导致创建新行
- 不在 USING 子句中的行不能影响数据库中的行
如果您不希望更新现有行,请确保其匹配行永远不会进入 USING 中的语句所呈现的结果集中。这可能意味着在 USING 中进行连接。这很好
示例:
MERGE Customers USING (
SELECT
s.CustomerID,
s.Name,
'Waiting' as Stat
FROM
Staging s
INNER JOIN Existing e on s.CustomerId = e.CustomerId
WHERE
e.Status <> 'Booked' --ignore all existing booked rows
) foo
...
using 语句中的这个连接确保与现有 "Booked" 行相关的暂存行永远不会进入 USING 生成的结果集中。因此它不会导致更新或插入
关键是要确保记录落入MATCHED逻辑,否则会通过NOT MATCHED逻辑生成新行。
为此,我们使用您的代码将您的条件添加到 MATCHED 逻辑中:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
WHEN MATCHED AND Customers.Status <> 'Booked' THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
这告诉合并匹配 CustomerID 上的所有内容。当它找到匹配项时,如果 Status <> 'Booked'
,则告诉它仅 运行 更新
考虑 table:
中存在的数据客户
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyd | Killed |
| 2 | Shelby Hawthorn | Booked |
我想 MERGEd 到 Customers table:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | name has 'e' on the end
| 2 | Shelby Blanken | Waiting | different last name
| 3 | Jessica Bogden | Waiting | totally new row
所以我可以想出近似的伪代码 MERGE 语句:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
WHEN MATCHED THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
这将合并它们:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | Last name spelling updated
| 2 | Shelby Blanken | Waiting | Last name changed
| 3 | Jessica Bogden | Waiting | New row added
但只更新了一些行
除了需要注意的是,我不想为 Booked
的客户更新任何现有行。换句话说,我希望最终结果是:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | updated existing row spelling
| 2 | Shelby Hawthorn | Booked | not updated because they're booked
| 3 | Jessica Bogden | Waiting | inserted new row
我的第一个猜测是 UPDATE
有一个 where 子句:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
WHEN MATCHED THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHERE Status <> 'Booked' -- <--------- it's the matching row; but don't update it
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
但这不是有效的语法。
我的第二个猜测是将条件添加到 ON
子句:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
AND Customers.Status <> 'Booked'
WHEN MATCHED THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHERE Status <> 'Booked' --it's the matching row; but don't update it
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
但现在该行不匹配,它们将根据 not matched by target 规则插入:
| CustomerID | Name | Status |
|------------|-----------------|--------------------|
| 1 | Ian Boyde | Waiting | updated existing row
| 2 | Shelby Hawthorn | Booked | not matched bcause booked
| 3 | Jessica Bogden | Waiting | inserted new row
| 4 | Shelby Blanden | Waiting | Mistakenly inserted because not matched by target
走出困境的出路是什么?
合并语句由 USING 子句驱动。
- USING 中 匹配 现有行的行导致现有行更新。
- USING 中的行不匹配 现有行导致创建新行
- 不在 USING 子句中的行不能影响数据库中的行
如果您不希望更新现有行,请确保其匹配行永远不会进入 USING 中的语句所呈现的结果集中。这可能意味着在 USING 中进行连接。这很好
示例:
MERGE Customers USING (
SELECT
s.CustomerID,
s.Name,
'Waiting' as Stat
FROM
Staging s
INNER JOIN Existing e on s.CustomerId = e.CustomerId
WHERE
e.Status <> 'Booked' --ignore all existing booked rows
) foo
...
using 语句中的这个连接确保与现有 "Booked" 行相关的暂存行永远不会进入 USING 生成的结果集中。因此它不会导致更新或插入
关键是要确保记录落入MATCHED逻辑,否则会通过NOT MATCHED逻辑生成新行。
为此,我们使用您的代码将您的条件添加到 MATCHED 逻辑中:
MERGE Customers USING (
SELECT CustomerID, Name, 'Waiting' FROM Staging) foo
ON Customers.CustomerID = foo.CustomerID
WHEN MATCHED AND Customers.Status <> 'Booked' THEN
UPDATE SET Name = foo.Name, Status = foo.Status
WHEN NOT MATCHED BY TARGET THEN
INSERT (Name, Status)
VALUES (Name, Status);
这告诉合并匹配 CustomerID 上的所有内容。当它找到匹配项时,如果 Status <> 'Booked'
,则告诉它仅 运行 更新