【问题标题】:SQL Server MERGE multiple on clause variationsSQL Server MERGE 多个子句变体
【发布时间】:2016-12-14 10:16:16
【问题描述】:

我正在使用 MERGE 语句在我的数据库中插入/更新记录。

我的源表包含三列,用于确定是否需要插入或更新记录。我的问题出现在 ON 子句中——目标表和源表使用三列连接,但是如何连接有很多变化。 (见下例)

我知道可以使用 AND / OR 运算符来实现这一点,但这会变得混乱且难以维护。我想知道是否有更有效的方法?

我的代码示例如下:

   MERGE Target_Table as t
   USING (select @param1, @param2, @param3)       
      AS s (col1, col2, col3)
      ON (t.col1 = s.col1
     AND t.col2 = s.col2
     AND t.col3 = s.col3)
      OR (t.col1 = s.col2
     AND t.col2 = s.col1
     AND t.col3 = s.col3)
    WHEN
 MATCHED
    THEN […update…]
    WHEN
     NOT
 MATCHED
    THEN […insert…]

提前致谢!

【问题讨论】:

  • 根据您为我列出的内容很难判断。任何列可以匹配另一个表中的任何其他列吗?恕我直言,可读性几乎与性能一样重要。尽管我确定您知道,由于您使用多个 AND / OR 运算符,请注意记住 SQL Server 在评估这些运算符时的优先级。 msdn.microsoft.com/en-us/library/ms190276.aspx
  • 您好,感谢您的回复。是的,我在源表中使用的三个变量可以以任意顺序匹配目标表中的三列中的任何一列。此外,我将示例限制为三个变量,但最多可以有六个。我想看看是否有更好的方法来评估数据并查看是否在任何列中找到变量
  • 所有参数是唯一的还是这些值可以相互相等?例如,param1 和 param2 可以都是“1”吗?

标签: sql sql-server stored-procedures merge


【解决方案1】:

您可以以不同的方式构建源表,因此您可以在合并条件之前构建组合,而不是使用OR。例如

DECLARE @param1 INT = 1, 
        @param2 INT = 2, 
        @param3 INT = 3;   


WITH Params AS
(   SELECT  pValue, pNumber
    FROM    (VALUES (@param1, 1), (@param2, 2), (@param3, 3)) p (pValue, pNumber)
)
SELECT  Col1 = p1.Pvalue, Col2 = p2.Pvalue, Col3 = p3.Pvalue
FROM    Params AS P1
        INNER JOIN Params AS p2
            ON p2.pNumber NOT IN (p1.pNumber)
        INNER JOIN Params AS p3
            ON p3.pNumber NOT IN (p1.pNumber, p2.pNumber);

这为您提供了 6 种组合(每个连接确保您没有重复使用相同的参数):

Col1    Col2    Col3
------------------
2       3       1
3       2       1
1       3       2
3       1       2
1       2       3
2       1       3

因此您的MERGE 条件变得更加简单:

WITH Params AS
(   SELECT  pValue, pNumber
    FROM    (VALUES (@param1, 1), (@param2, 2), (@param3, 3)) p (pValue, pNumber)
), SourceTable AS
(   SELECT  Col1 = p1.Pvalue, Col2 = p2.Pvalue, Col3 = p3.Pvalue
    FROM    Params AS P1
            INNER JOIN Params AS p2
                ON p2.pNumber NOT IN (p1.pNumber)
            INNER JOIN Params AS p3
                ON p3.pNumber NOT IN (p1.pNumber, p2.pNumber)
)
MERGE Target_Table AS t
USING SourceTable AS s
    ON t.col1 = s.col1
    AND t.col2 = s.col2
    AND t.col3 = s.col3
WHEN MATCHED THEN […update…]
WHEN NOT MATCHED THEN […insert…];

这也使得添加更多参数变得更加容易,因此第四个参数只需要在 CTE params 中增加一行,而不是一组全新的 OR 条件

DECLARE @param1 INT = 1, 
        @param2 INT = 2, 
        @param3 INT = 3, 
        @param4 INT = 4;   


WITH Params AS
(   SELECT  pValue, pNumber
    FROM    (VALUES (@param1, 1), (@param2, 2), (@param3, 3), (@Param4, 4)) p (pValue, pNumber)
)
SELECT  Col1 = p1.Pvalue, Col2 = p2.Pvalue, Col3 = p3.Pvalue
FROM    Params AS P1
        INNER JOIN Params AS p2
            ON p2.pNumber NOT IN (p1.pNumber)
        INNER JOIN Params AS p3
            ON p3.pNumber NOT IN (p1.pNumber, p2.pNumber);

然后给出所有 24 种组合,没有太多额外的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2011-09-03
    • 2015-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多