Where子句为NULL的案例

时间:2018-09-25 19:31:33

标签: sql sql-server

我正在创建一个查询(最终将在存储过程中使用),该查询具有在表单中输入哪些条件的多种变体。有时可以有一个条目,有时没有。有时数据字段具有值,有时为NULL。

我的表单中的字段是NAME,SSN和DRLICENSE。

DECLARE @name VARCHAR(30);    
DECLARE @ssn VARCHAR(10);
DECLARE @drlic VARCHAR(10);
--(if for example, someone enters data in two of the fields like this...)
SET @name = 'SMITH'
SET @drlic = 'D'

(In stored procedure)
SET @name = @name + '%'
SET @ssn = @ssn + '%'
SET @drlic = @drlic + '%'

SELECT 
    NAME,
    SSN,
    DRLICENSE
FROM 
    TABLE
WHERE 
    NAME LIKE CASE WHEN LEN(@name) > 1 THEN @name ELSE NAME END
    AND SSN LIKE CASE WHEN len(@ssn) > 1 THEN @ssn ELSE SSN END
    AND DRLICENSE LIKE CASE WHEN LEN(@drlic) > 1 THEN @drlic ELSE DRLICENSE END

我的case语句后面的想法是检查变量的使用情况,并在namessndrlicense是部分条目的情况下执行类似的操作。

我的问题是:如何在表列中说明NULL的情况(即,SSN LIKE SSNSSNNULL不起作用,因为SSN IS NULL需要在那里)。

6 个答案:

答案 0 :(得分:2)

这不能很好地执行,特别是因为您使用的是LIKE,但是括号在这里很重要

where ((@name is null or name like '%' + @name + '%') or ( name is null))
and ((@ssn is null or ssn like '%' + @ssn + '%') or (ssn is null))
and ((@drlic is null or DRLICENSE like '%' + @drlic + '%') or (DRLICENSE is null))

这将返回这些列中的NULL值,无论是否传入参数。如果您不希望NULL,则只需从每一行中删除or ( name is null))部分。我不确定你的帖子。

答案 1 :(得分:1)

if length(@foo) <= 1
  set @foo = NULL
if length(@bar) <= 1
  set @bar = NULL
...
WHERE (@foo is NULL or t.foo = @foo)
  AND (@bar is NULL or t.bar like @bar)
OPTION (RECOMPILE)

答案 2 :(得分:1)

您可以内联将通配符添加到参数值,也可以内联添加空检查。也不需要CASE语句。对于每个参数/列值,如果参数为null或列值为null或列值传入的参数值开头,则结果返回true

在哪里声明:

WHERE (Name IS NULL OR @name IS NULL OR Name LIKE @name + '%')
  AND (SSN IS NULL OR @ssn IS NULL OR SSN LIKE @ssn + '%')
  AND (DRLICENSE IS NULL OR @drlic IS NULL OR DRLICENSE LIKE @drlic + '%')

这里的关键是,如果要使用的传入值是null或列值是null(我假设您不想对其进行过滤,则{{1} }}。

答案 3 :(得分:1)

这应该做到:

WHERE (@name  IS NULL OR name      LIKE @name  + '%')
AND   (@ssn   IS NULL OR ssn       LIKE @ssn   + '%')
AND   (@drlic IS NULL OR drlicense LIKE @drlic + '%')

请注意,例如,如果用户搜索name = foo,则它将返回与foo%匹配的行,而不是具有NULL名称的行。

答案 4 :(得分:0)

如果我理解正确,那么您想要一个NULL-安全的相等性。也就是说,您要NULL匹配NULL,并且值要匹配值。所以:

where (name = @name or (name is null and @name is null)) and
      (ssn = @ssn or (ssn is null and @ssn is null)) and
      (drlicense = @drlicense or (drlicense is null and @drlicense is null))

,或者是一个有趣的变体:

where (select count(*)
       from (select distinct *
             from (values (name, 'name'), (@name, 'name'), (ssn, 'ssn'), (@ssn, 'ssn'), (drlicense, 'drlicense'), (@drlicense, 'drlicense')
                  v(val, which)
            ) x
      ) = 3

这是使用group by语义来组合NULL值。

或者,如果您想进行一些混淆:

where nullif(name, @name) is null and nullif(@name, name) is null and
      nullif(ssn, @ssn) is null and nullif(@ssn, ssn) is null and
      nullif(drlicense, @drlicense) is null and nullif(@drlicense, drlicense) is null

答案 5 :(得分:0)

您可以使用ISNULL(),在像您这样的情况下非常有用。

SELECT 
    NAME,
    SSN,
    DRLICENSE
FROM 
    TABLE
WHERE 
    ISNULL(NAME,0)      LIKE ISNULL(ISNULL(@name, NAME),0)
AND ISNULL(SSN,0)       LIKE ISNULL(ISNULL(@ssn, SSN),0)
AND ISNULL(DRLICENSE,0) LIKE ISNULL(ISNULL(@drlic, DRLICENSE),0)

如果列值为NULL,则此方法将用列值替换NULL值,然后将两者都设置为0(将为0 = 0,始终为true)。