39

以下:

MERGE dbo.commissions_history AS target
USING (SELECT @amount, @requestID) AS source (amount, request)
ON (target.request = source.request)
WHEN MATCHED THEN
    UPDATE SET amount = source.amount
WHEN NOT MATCHED THEN
    INSERT (request, amount)
    VALUES (source.request, source.amount);

来自https://stackoverflow.com/a/2967983/857994是一种非常漂亮的插入/更新方式(并通过一些额外的工作删除)。即使经过一些谷歌搜索,我也很难理解。

有人可以请:

  • 用简单的术语解释一下——在这种情况下,MSDN 文档破坏了我的大脑。
  • 告诉我如何修改它,以便用户可以输入数量和请求的值,而不是从另一个数据库位置选择它们?

基本上,我想使用它从 C# 应用程序中插入/更新,其中包含从我获取的 XML 文件中获取的信息。因此,我需要了解如何手动制定查询,以使用这种机制将解析的数据放入数据库。

4

2 回答 2

75

如果您不熟悉join 语句,那么这就是您需要开始的地方。了解连接的工作原理是其余部分的关键。一旦您熟悉了联接,那么通过将其视为完全联接以及如何处理匹配或不匹配的行的说明,理解合并是最容易的。

因此,使用提供的代码示例让我们看一下 Commissions_history 表

|  Amount  |   Request  |   <other fields> |
--------------------------------------------
|  12.00   |   1234     |   <other data>   |
|  14.00   |   1235     |   <other data>   |
|  15.00   |   1236     |   <other data>   |

合并语句在称为“目标”的表和返回称为“源”的表(或在逻辑上与 CTE 等表非常相似的结果集)的表达式之间创建完全连接。

在给出的示例中,它使用变量作为源,我们假设这些变量已由用户设置或作为参数传递。

DECLARE @Amount Decimal = 18.00;
DECLARE @Request Int = 1234;

MERGE dbo.commissions_history AS target       
USING (SELECT @amount, @requestID) AS source (amount, request)       
ON (target.request = source.request)   

将其视为联接时创建以下结果集。

|  Amount  |   Request  |   <other fields> | Source.Amount | Source.Request  |
------------------------------------------------------------------------------
|  12.00   |   1234     |   <other data>   |   18.00       |     1234        |
|  14.00   |   1235     |   <other data>   |   null        |     null        |
|  15.00   |   1236     |   <other data>   |   null        |     null        |

在找到匹配项的情况下,使用给出的关于对目标做什么的说明。

WHEN MATCHED THEN        
UPDATE SET amount = source.amount    

生成的目标表现在看起来像这样。请求 1234 的行更新为 18。

|  Amount  |   Request  |   <other fields> |
--------------------------------------------
|  18.00   |   1234     |   <other data>   |
|  14.00   |   1235     |   <other data>   |
|  15.00   |   1236     |   <other data>   |

由于找到了匹配项,因此没有其他任何事情发生。但是,可以说来自源的值是这样的。

DECLARE @Amount Decimal = 18.00;
DECLARE @Request Int = 1239;

生成的连接将如下所示:

|  Amount  |   Request  |   <other fields> | Source.Amount | Source.Request  |
------------------------------------------------------------------------------
|  12.00   |   1234     |   <other data>   |   null        |     null        |
|  14.00   |   1235     |   <other data>   |   null        |     null        |
|  15.00   |   1236     |   <other data>   |   null        |     null        |
|  null    |   null     |   null           |   18.00       |     1239        |

由于在目标中未找到匹配的行,因此该语句执行另一个子句。

WHEN NOT MATCHED THEN                                 
INSERT (request, amount)                                 
VALUES (source.request, source.amount);  

导致现在看起来像这样的目标表:

|  Amount  |   Request  |   <other fields> |
--------------------------------------------
|  12.00   |   1234     |   <other data>   |
|  14.00   |   1235     |   <other data>   |
|  15.00   |   1236     |   <other data>   |
|  18.00   |   1239     |   <other data>   |

合并语句真正的潜力是当源和目标都是大表时。因为它可以用一个简单的语句对每一行进行大量更新和/或插入。

最后一点。重要的是要记住not matched默认为完整的子句not matched by target,但是您可以指定not matched by source代替默认子句,或者添加到默认子句中。合并语句支持两种类型的不匹配(源中的记录不在目标中,或者目标中的记录不在源中,由 on 子句定义)。 您可以在 MSDN 上找到完整的文档、限制和完整的语法。

于 2012-04-18T23:28:11.533 回答
0

在给定的答案示例中,您已完成

DECLARE @Request Int

, 但在 SQL 中调用它如下:

SELECT @amount, @requestID

另一个将相同地命名和调用变量:

@amount vs. Amount -> @Amount & Amount
于 2015-05-11T10:19:16.600 回答