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