这个问题可以归结为更简单的问题,但我仍然很好奇SQL Server / TSQL与条件WHERE
条款的接近程度(以及为什么它们不存在的原因也是如此)有趣)。
我有一个存储过程,对于一些参数,它接受一个枚举数组(相应地转换为用户定义的表类型,它基本上模拟了一个int数组)。作为参考,数据类型如下:
CREATE TYPE myIntArray AS TABLE (
val INT
);
我的存储过程遵循以下几行(更改为更简单化):
CREATE PROCEDURE myProc
@homeID INT,
@name VARCHAR(500),
@hometype_enum myIntArray READONLY,
@country_enum myIntArray READONLY
AS
BEGIN
SELECT * FROM my_table
WHERE name=@name
END
GO
我想要做的是另外根据作为INT表传入的枚举数组的值来过滤查询结果,IFF它们甚至传入了值(表可能是空的) 。伪代码看起来像这样:
SELECT *
FROM my_table
WHERE name = @name
IF((SELECT COUNT(val) FROM @hometype_enum) > 0)
BEGIN
AND hometype IN (SELECT val FROM hometype_enum)
END
IF((SELECT COUNT(val) FROM @country_enum ) > 0)
BEGIN
AND country IN (SELECT val FROM country_enum )
END
这两个枚举是相互独立的,因此可以进行搜索并在没有枚举(两个表都为空),或者两个枚举或两个枚举的情况下进行过滤。
我的实际查询涉及多个列,表和联合(丑陋,我知道),因此它不如能够为每个场景复制/粘贴3行SELECT
一样好。我目前正在使用一些非常丑陋的临时表逻辑,我现在不会饶恕读者的眼睛。
除了弄清楚我的特定问题之外,我的主要问题是:SQL Server是否支持条件WHERE
子句语句(我确信它不是来自我的研究)?为什么这样(架构,时间复杂,空间复杂性问题)?是否有更多或更少的简洁方法来模拟条件子句,例如taking advantage of conditional short-circuiting?
感谢大家的见解。另一天的学习!
答案 0 :(得分:2)
正如评论中所建议的那样,处理这种条件where子句的最好方法是使用dynamic-sql ......就像....
CREATE PROCEDURE myProc
@homeID INT,
@name VARCHAR(500),
@hometype_enum myIntArray READONLY,
@country_enum myIntArray READONLY
AS
BEGIN
SET NOCOUNT ON
Declare @Sql NVarchar(MAX);
SET @Sql = N' SELECT * FROM my_table '
+ N' WHERE name = @name '
+ CASE WHEN EXISTS (Select * FROM @hometype_enum)
THEN N' AND hometype IN (SELECT val FROM hometype_enum) ' ELSE N' ' END
+ CASE WHEN EXISTS (Select * FROM @country_enum)
THEN N' AND country IN (SELECT val FROM country_enum ) ' ELSE N' ' END
Exec sp_executesql @Sql
,N'@homeID INT , @name VARCHAR(500),
@hometype_enum myIntArray, @country_enum myIntArray'
,@homeID
,@name
,@hometype_enum
,@country_enum
END
GO
使用sp_executesql
将允许sql server存储同一存储过程的参数化执行计划。对于相同存储过程的不同组/组合的不同执行计划以获得最佳性能。
答案 1 :(得分:2)
下面的一个也可以。不需要dynamic-sql。 MS SQL可以毫无问题地处理它(具有良好的性能)。
CREATE PROCEDURE myProc
@homeID INT,
@name VARCHAR(500),
@hometype_enum myIntArray READONLY,
@country_enum myIntArray READONLY
AS
BEGIN
SELECT * FROM my_table
WHERE name=@name
AND ( ( SELECT count(val) FROM @hometype_enum ) = 0
OR hometype IN (SELECT val FROM @hometype_enum) )
AND ( ( SELECT count(val) FROM @country_enum ) = 0
OR country IN (SELECT val FROM @country_enum) )
END
GO
OR
将为您完成工作。当第一部分:SELECT count(val) FROM @hometype_enum ) = 0
将返回true时,第二部分将不会被执行 - 空IN
子句没有错误。当第一部分将返回一些大于0的值时,将正确评估第二部分。