我应该如何针对可以为null的SQL变量测试字段?

时间:2009-06-16 16:53:12

标签: sql sql-server sql-server-2008 three-valued-logic

我有以下SQL:

CREATE TABLE tbFoo(
    a varchar(50) NULL,
) 


CREATE NONCLUSTERED INDEX IX_tbFoo_a ON tbFoo
(
    a ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)

insert into tbFoo select null
insert into tbFoo select 'test'

以下两个查询正常工作并按预期使用我的索引:

select * from tbFoo where a='test'
select * from tbFoo where a is null

现在,让我假装我想将比较值存储在变量中,如下所示:

declare @a varchar(50)
select @a = NULL

如果@a为null,则以下查询不会返回预期结果,因为我应该使用“is”运算符而不是“=”

select * from tbFoo where a=@a 

如果@a为null(由于'test'行强制评估第二个括号),以下方法可以正常进行表扫描

select * from tbFoo where (a is null and @a is null) or (a=@a)

最终,我提出了这个解决方案,它运行正常并使用我的索引:

select * from tbFoo where (a is null and @a is null) or (@a is not null and a=@a)

我对情况的分析是否正确?

有没有更好的方法来处理这种情况?

8 个答案:

答案 0 :(得分:3)

  

最终,我提出了这个解决方案,它运行正常并使用我的索引:

在SQL Server 2008中,您可以根据排除NULL的谓词定义筛选索引:

CREATE UNIQUE NONCLUSTERED INDEX IX_tbFoo_a 
ON tbFoo (a)
WHERE a IS NOT NULL;

答案 1 :(得分:1)

没有任何东西“等于”NULL ......这就是NULL的一点。

您的解决方案将正常运行。我对查询优化器如何处理较短版本感到惊讶。我认为在测试与表扫描的相等性之前测试一个for NULL将是一个明智的选择。

答案 2 :(得分:1)

另一种可能性是使用设置ansi nulls来关闭

set ansi_nulls off

declare @a varchar(50)
select @a = NULL

select * from tbFoo where a=@a

set ansi_nulls on

请记住,您正在摆脱此处的默认行为

答案 3 :(得分:1)

也许您的数据库引擎会优化您自动获得的内容,但在我看来,以下内容会更有效:

if @a IS NULL
    select * from tbFoo where a is null
else
    select * from tbFoo where a = @a

我的理由是,您只需执行一次if @a IS NULL条件,而不是检查数据库中的每一行。但是,质量数据库引擎应该能够将您的代码转换为与此相同的数据计划。

答案 4 :(得分:0)

这就是我所做的。它非常灵活。 我假设@a是sproc的参数。 'somethingweird'可能是你在记录集中看不到的东西'~~~'或其他什么。

set @a = isnull(@a,'somethingweird')
select * from tbFoo where isnull(a,'somethingweird')=@a

答案 5 :(得分:0)

我家里没有一个实例可以玩,但我可以看到桌面扫描变得非常烦人。一种可能的替代方法是使用UNION代替OR运算符......

select * from tbFoo where (a is null and @a is null)
UNION ALL
select * from tbFoo where (a=@a and @a is not null)

(我不确定“@a is not null”会对性能产生什么影响,但我的直觉是包含它。这是一个常量表达式,应该允许优化器知道整个条件总是失败。我的技术总是发挥,看看什么效果最好。)

我发现这个UNION技巧有两个属性:
- 它可以通过简化查询来显着提高性能 - 它会使代码具有多个连接,并导致严重的维护问题

然而,生活是一种平衡的行为:)

答案 6 :(得分:0)

只是ISNULL双方都这样......

DECLARE @random VARCHAR(50)
SELECT  @random = 'text that never appears in your table'

SELECT * FROM @tbFoo WHERE ISNULL(a, @random) = ISNULL(@a, @random)

答案 7 :(得分:0)

你的分析是正确的 - 这就是三值逻辑使生活变得困难的原因。

@StriplingWarrior的建议很好;它通过执行不同的SQL来解决问题,具体取决于变量是否为null。如果不可能,那么你需要重复使用主变量的冗长解决方案。