Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 更有效的双聚结连接方案_Sql_Sql Server_Tsql_Stored Procedures_Coalesce - Fatal编程技术网

Sql 更有效的双聚结连接方案

Sql 更有效的双聚结连接方案,sql,sql-server,tsql,stored-procedures,coalesce,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

我有一个程序,其版本略为复杂,如下所示:

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,或者它们都是相同的notnull值,则第二次匹配成功

我的问题是:有没有一种更有效甚至更易读的方法来做到这一点


我已经用过这种方法好几次了,而且每次主观上的肮脏都会让我感到有些不愉快。

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

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

SELECT @ID ID

我认为应该这样做——如果@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 

不知道这是否更可取

SELECT @ID = ID
FROM Table1
WHERE Match1 = @Match1
    AND ((Match2 = @Match2) OR Coalesce(Match2,@Match2) IS NULL)
有没有一种更有效或更易读的方法

您提供的使用COALESCE/etc的示例如下。您需要将内容分开,以便只运行查询中需要显示的内容:

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是唯一真正的替代方案。我强烈建议在进一步阅读之前阅读:

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

避免使用或不使用等

如果任一侧为空,则EXCEPT位不返回任何行 Match2@Match2表示排除非空非匹配 像这样的

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

如果Match2为空,那么null=null是未知的不是真的。@Martin-ah是的,很好。此解决方案要求Match2不为null不会Match2=@Match2 null如果其中一个为null,则整个子句都为null?否。未知或true=true且未知或false=unknown。空逻辑甚至比我一开始担心的更令人难以置信。尽管它是有道理的。如果or的一部分为真,那么其余部分是真还是假都无关紧要。我们知道整个语句都是真的。使用IsNull而不是两值合并可能会稍微提高速度?Match1=@Match1位是可搜索的,尽管这取决于它的选择性,这可能会缓解这种情况。非常有趣,我可能不得不修改我以前的一些查询设计。Match2部分可能不到30行,而Match1大约有50000行。@Martin Smith:是的,Match1的内容是可搜索的,只有在括号中使用is NULL/COALESCE/ISNULL时才是不可搜索的。@OMG假设Match1上有一个复合索引,match2 SQL Server将在match1上执行搜索,但随后必须扫描30个匹配行以评估第二部分。随着时间的推移,加起来可能是+1