2016-08-08 137 views
0

我正在使用MERGE语句在我的数据库中插入/更新记录。SQL Server MERGE multiple on子句变体

我的源表包含三列,用于标识记录是否需要插入或更新。我的问题出现在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…] 

谢谢!

+0

根据您列出的内容很难说清楚。任何列可以与其他表中的其他列匹配吗?可读性与性能恕我直言一样重要。虽然我确定你知道,因为你正在使用多个AND/OR操作符,所以要小心记住SQL Server在评估这些操作时的优先级。 https://msdn.microsoft.com/en-us/library/ms190276.aspx – scsimon

+0

嗨,谢谢你的回复。是的,我在源表中使用的三个变量可以以任意顺序匹配目标表中的三列中的任何一列。此外,我已将该示例限制为三个变量,但最多可以有六个。我想看看是否有更好的方法来评估数据并查看是否在任何列中找到变量 – ccalgie

+0

所有参数都是唯一的还是可以使这些值相等?例如,param1和param2都可以是“1”吗? –

回答

0

您可以以不同的方式构建源表,因此,您可以在合并条件之前构建组合,而不是使用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个组合,没有太多额外的代码。