Sql 与WHERE子句合并

Sql 与WHERE子句合并,sql,sql-server,sql-merge,Sql,Sql Server,Sql Merge,考虑表中存在的数据: 顾客 以及我希望合并到Customers表中的行: 因此,我可以得出近似的伪代码合并语句: 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 WH

考虑表中存在的数据:

顾客

以及我希望合并到Customers表中的行:

因此,我可以得出近似的伪代码合并语句:

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
但只更新一些行 除了一个警告,我不想为已预订的客户更新任何现有行。换句话说,我希望最终结果是:

| 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
我的第一个猜测是更新包含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);
但现在该行将不匹配,它们将被插入到“不匹配目标”规则下:


解决这个难题的方法是什么?

合并语句由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语句中的这种连接确保与现有预订行相关的暂存行永远不会进入using语句生成的结果集中。因此,它不能导致update或insert语句由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语句中的这种连接确保与现有预订行相关的暂存行永远不会进入using语句生成的结果集中。因此,它不能导致更新或插入。关键是要确保记录属于匹配的逻辑,否则它将通过不匹配的逻辑生成新行

为此,我们使用您的代码将您的条件添加到匹配的逻辑中:

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上的所有内容。当它找到匹配项时,您告诉它仅在状态为“Booked”(已预订)的情况下运行更新。关键是要确保记录符合匹配逻辑,否则它将通过不匹配逻辑生成新行

为此,我们使用您的代码将您的条件添加到匹配的逻辑中:

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上的所有内容。当它找到匹配项时,您告诉它仅在状态为“Booked”时运行更新

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
...
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);