3

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

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 值为空,或者它们都是相同(非空)值,则第二次匹配成功。

我的问题是:有没有更有效(甚至更易读)的方式来做到这一点?

这种方法我用过几次,每次都觉得有点被玷污(诚然,主观肮脏)。

4

5 回答 5

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 是唯一真正的替代方案。在进一步阅读之前,我强烈推荐阅读动态 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
于 2010-09-29T17:20:10.857 回答
4

避免 OR 和 ISNULL 等

  • 如果任一侧为空,则 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
于 2010-09-29T17:33:31.840 回答
1

不知道这是否更可取。

SELECT @ID = ID
FROM Table1
WHERE Match1 = @Match1
    AND ((Match2 = @Match2) OR Coalesce(Match2,@Match2) IS NULL)
于 2010-09-29T17:07:13.000 回答
0

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

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

SELECT @ID ID
于 2010-09-29T17:03:08.653 回答
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 
于 2010-09-29T17:07:12.920 回答