【问题标题】:Optional Arguments in WHERE Clause [duplicate]WHERE 子句中的可选参数
【发布时间】:2012-04-28 11:06:02
【问题描述】:

让我们假设有一个具有 3 个参数的存储过程。在所有的可能性中,我希望通过一个 WHERE 子句来实现这一点,而不会因为过多地使用 () AND () OR () 而失控......

例子:

    //Params
@CITY VARCHAR(100) = NULL,
@GENDER VARCHAR(100) = NULL,
@AGE VARCHAR(100) = NULL

我想你可以为每个变量使用IF BEGIN ... END 如果存在,但这会使代码比预期的要长很多..

下面的这个方法行不通,因为它太长了(大约有 10 个这样的不同字段,但示例只有 3 个。)而且我不确定它是否直接提取了独特的值......

SELECT NAME FROM TABLE 
WHERE (
(CITY=@CITY AND GENDER=@GENDER AND AGE=@AGE)
OR (CITY=@CITY AND GENDER=@GENDER)
OR (GENDER=@GENDER AND AGE=@AGE)
OR (CITY=@CITY AND AGE=@AGE)
OR (CITY=@CITY)
OR (GENDER=@GENDER)
OR (AGE=@AGE)
)

有没有更短更有效的方法来做到这一点?

如果是,该方法最好也与 JOIN 兼容。

【问题讨论】:

  • 旁注:当定义VARCHAR() - 作为存储过程或局部变量的参数时 - 应该总是有一个长度定义!否则你可能会无意中得到VARCHAR(1) 字符串...
  • 可选字段,意思是如果没有或NULL值,那么不要在Where子句中显示,可以吗?

标签: sql sql-server sql-server-2008


【解决方案1】:

除了ISNULL / COALESCE 选项,您可以测试参数是否为空:

SELECT NAME  
FROM TABLE  
WHERE  
    (@City IS NULL OR City = @City)
AND 
    (@Gender IS NULL OR Gender = @Gender)
AND 
    (@Age IS NULL OR Age = @Age) 

【讨论】:

  • 我知道现在发表评论有点太晚了,但请小心这种方法,因为 SQL Server 不保证评估的顺序(它肯定不会短路) .所以你最好让 SQL Server 做所有不必要的检查。
  • @IlyaChernomordik:还有冲下山的性能。
  • @IlyaChernomordik 那么有什么更好的方法呢?想到了动态sql,但是又带来了维护、代码清理等问题,没有其他更好的办法了吗?
  • 至少我不知道 :) 如果动态 SQL 变得足够复杂并开始影响性能,我会使用它
  • 使用 OR 和动态 sql 查询会导致性能下降,似乎最好的选择是使用 IF ..ELSE 或 Case 语句,我认为通过这种方式可以制定两个执行计划并将其缓存,我有这样一个问题,请先看看它。 stackoverflow.com/questions/46386090/…
【解决方案2】:

这个呢?

SELECT
    NAME
FROM TABLE 
WHERE CITY = COALESCE(@CITY, CITY)
    AND GENDER = COALESCE(@GENDER, GENDER)
    AND AGE = COALESCE(@AGE, AGE)

【讨论】:

  • 漂亮!如果遇到空变量,SQL Server 希望能够优化掉这些条件。测试会很有趣。
  • 这很好,但如果CITY@CITY 都为null,则不会包含记录,因为null 不等于null(除非ANSI_NULLS 设置为OFF) .
【解决方案3】:

试试这样的:

SELECT NAME 
FROM TABLE 
WHERE 
    City = IsNull(@City, City) AND
    Gender = IsNull(@Gender, Gender) AND
    Age = IsNull(@Age, Age)

或者:

SELECT NAME 
FROM TABLE 
WHERE 
    (City = @City OR @City IS NULL) AND
    (Gender = @Gender OR @Gender IS NULL) AND
    (Age = @Age OR @Age IS NULL)

【讨论】:

  • 我认为您的第一个示例可能会减少它,让我检查一下.. brb。
  • 关于第一个选项.... NULL 等于 NULL 吗?
  • Select * From Table Where NULL IS NULL 将返回所有行。在这种情况下没问题,因为这意味着如果您将参数传递给 NULL 值,您就不想按参数进行过滤。
  • 是但 Select * From Table Where NULL = NULL 将不包括具有空列值的行。在具有包含 NULL 的可空列的表上进行测试。例如:SELECT * FROM mytable WHERE mycolumn = IsNull(null, mycolumn)
  • 我以前从未想到过那种 City = IsNull(@City, City) 格式。外观漂亮干净。
【解决方案4】:
SELECT NAME   
FROM TABLE   
WHERE       
  City = case when isnull(@City ,'') = '' then City
                        else @City end
AND      
  Gender = case when isnull(@Gender ,'') = '' then Gender
                        else @Gender end
AND  
  Age = case when isnull(@Age ,0) = 0 then Age
                        else @Age end    

【讨论】:

  • 我怀疑 City=City 条件和一般 Column =Column 条件是无效的条件,例如 null = null 可能导致我们到 UNKNOWN,另一方面,如果我们的列不是 null ,我们最终得到一个完整的 column = column condition 扫描表。
【解决方案5】:

可能是这样的:

create procedure myProc
    --Params
@CITY VARCHAR(100) = NULL,
@GENDER VARCHAR(100) = NULL,
@AGE VARCHAR(100) = NULL
as

SELECT NAME FROM [TABLE]
WHERE ISNULL(CITY,'')=ISNULL(@CITY,ISNULL(CITY,''))
AND ISNULL(GENDER,'')=ISNULL(@GENDER,ISNULL(GENDER,''))
AND ISNULL(AGE,'')=ISNULL(@AGE,ISNULL(AGE,''))
go

假设 WHERE 子句中的列可以为空,使用 ISNULL 避免空比较。

【讨论】:

  • uggghhh.. 我想避免那样做.. 像“IsNull”这样的东西?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多