更高效的双重合并加入替代方案

时间:2010-09-29 16:58:00

标签: sql sql-server tsql stored-procedures coalesce

我的程序有一个(稍微复杂一点)以下的版本:

CREATE PROC sp_Find_ID (
    @Match1 varchar(10),
    @Match2 varchar(10)
) AS

DECLARE @ID int

SELECT @ID = ID
FROM Table1
WHERE Match1 = @Match1
    AND Coalesce(Match2,@Match2,'') = Coalesce(@Match2,Match2,'')

SELECT @ID ID

基本上Match1是强制匹配,但Match2在过程的输入和被搜索的表上都是可选的。第二个匹配成功,其中输入和/或表Match2值为null,或者它们都是相同(非空)值。

我的问题是:是否有更高效(甚至更可读)的方式?

我已经使用过这种方法几次,每次都感觉有点玷污(主观上是肮脏的)。

5 个答案:

答案 0 :(得分:4)

  

是否有更高效(或更可读)的方式?

您使用COALESCE / etc提供的示例是non-sargable。您需要将事物分开,以便只运行查询中需要出现的内容

DECLARE @ID int

IF @Match2 IS NOT NULL
BEGIN

  SELECT @ID = t.id
    FROM TABLE1 t
   WHERE t.match1 = @Match1
     AND (t.match2 = @Match2 OR t.match2 IS NULL)

END
ELSE
BEGIN

  SELECT @ID = t.id
    FROM TABLE1 t
   WHERE t.match1 = @Match1

END

SELECT @ID ID

如果您希望在单个SQL语句中进行此操作,则动态SQL是唯一真正的替代方法。我强烈建议您在阅读之前阅读The curse and blessing of dynamic SQL

DECLARE @SQL NVARCHAR(MAX)
    SET @SQL = N' SELECT @ID = t.id
                    FROM TABLE1 t
                   WHERE t.match1 = @Match1 '

    SET @SQL = @SQL + CASE 
                        WHEN @Match2 IS NOT NULL THEN
                          ' AND (t.match2 = @Match2 OR t.match2 IS NULL) ' 
                        ELSE 
                          ' '
                      END

BEGIN

  EXEC sp_executesql @SQL,
                     N'@ID INT OUTPUT, @Match1 VARCHAR(10), @Match2 VARCHAR(10)',
                     @ID, @Match1, @Match2

END

答案 1 :(得分:4)

避免OR和ISNULL等

  • 如果任一方为IS NULL
  • ,则EXCEPT位不返回任何行
  • Match2<> @ Match2表示排除非NULL不匹配

像这样的东西

DROP TABLE dbo.Table1

CREATE TABLE dbo.Table1 (ID int NOT NULL, Match1 int NOT NULL, Match2 int NULL)
INSERT dbo.Table1 VALUES (1, 55, 99), (2, 55, NULL)

DECLARE @Match1 int = 55, @Match2 int

SELECT ID
FROM
    (
    SELECT ID FROM Table1 WHERE Match1 = @Match1
    EXCEPT -- @Match2 = NULL, match both rows (99, NULL)
    SELECT ID FROM Table1 WHERE Match2 <> @Match2
    ) foo

SET @Match2 = -1
SELECT ID
FROM
    (
    SELECT ID FROM Table1 WHERE Match1 = @Match1
    EXCEPT -- @Match2 = -1, match ID = 2 only where Match2 IS NULL
    SELECT ID FROM Table1 WHERE Match2 <> @Match2
    ) foo

答案 2 :(得分:1)

不知道这是否更合适。

SELECT @ID = ID
FROM Table1
WHERE Match1 = @Match1
    AND ((Match2 = @Match2) OR Coalesce(Match2,@Match2) IS NULL)

答案 3 :(得分:0)

对我来说似乎很简单?我一定错过了什么......你不需要Coalesce

SELECT @ID = ID
 FROM Table1
 WHERE Match1 = @Match1
    AND (
          (Match2 is null and  @Match2 is null)
           or
           @Match2=Match2
    )

SELECT @ID ID

答案 4 :(得分:0)

我认为应该这样做 - 假设@Match2值为NULL,如果它是可选的。

CREATE PROC sp_Find_ID (
    @Match1 varchar(10),
    @Match2 varchar(10)
) AS

DECLARE @ID int

SELECT @ID = ID
FROM Table1
WHERE Match1 = @Match1
    AND Match2 = IsNull(@Match2, Match2)

SELECT @ID ID