NULL和SET ANSI_NULLS OFF

时间:2016-05-02 08:12:26

标签: sql sql-server

我有一些SQL查询具有一列可以采用NULL的表 在下面的代码中,@term_type_id可以是NULL,而列term_type_id可以有NULL个值。
因此,如果@term_type_id有值,则下面的代码有效,但如果@term_type_idNULL,则无法使用。 设置SET ANSI_NULLS OFF是解决问题的方法,但我知道这会在某个阶段折旧。

SELECT      [date],value FROM history 
WHERE       id=@id 
AND         data_type_id=@data_type_id
AND         quote_type_id=@quote_type_id 
AND         update_type_id=@update_type_id
AND         term_type_id=@term_type_id
AND         source_id=@source_id
AND         ([date]>=@temp_from_date and [date]<=@temp_to_date)
ORDER BY    [date]

我过去所做的就是拥有这样的东西

if @term_type_id is NULL 
BEGIN
    SELECT ......
    WHERE .....
    AND term_type_id IS NULL
END
BEGIN
    SELECT ......
    WHERE .....
    AND term_type_id = @term_type_id
END

虽然这有效,但它非常冗长,使代码难以阅读和维护 有没有人有比使用SET ANSI_NULLS OFF更好的解决方案,或者必须编写条件代码只是为了管理某些东西可能是值或NULL的情况?

BTW - 当我使用SET ANSI_NULLS OFF时,我只针对特定查询执行此操作,然后将其重新打开。我确实理解为什么这是不赞成的原因,但这是以编写无意义的代码来绕过一个纯粹的&#39; NULL的视图。

5 个答案:

答案 0 :(得分:1)

由于列和参数都可以为null,因此您应该同时处理这两种情况:

SELECT      [date],value FROM history 
WHERE       id=@id 
AND         data_type_id=@data_type_id
AND         quote_type_id=@quote_type_id 
AND         update_type_id=@update_type_id
AND         ((term_type_id IS NULL AND @term_type_id IS NULL) OR term_type_id = @term_type_id)
AND         source_id=@source_id
AND         ([date]>=@temp_from_date and [date]<=@temp_to_date)
ORDER BY    [date]

请注意,这只会在列和参数都为null时返回结果,或者它们都不为null。

答案 1 :(得分:1)

Ben,if @term_type_id is NULL SELECT @term_type_id=-1的更好解决方案 将使用isnull(@term_type_id,-1)

答案 2 :(得分:0)

试试这个,这对两种情况都有效。

SELECT ......
WHERE .....
    AND ISNULL(term_type_id,-1) = ISNULL(@term_type_id,-1)    

您可以使用任何静态值代替-1

或者您可以使用以下内容

SELECT ......
WHERE .....
    AND (   (@term_type_id IS NULL AND term_type_id IS NULL) 
            OR term_type_id = @term_type_id 
        )

答案 3 :(得分:0)

啊 - 是的 - 谢谢你的快速反应。我想我刚刚提出了一个更好的解决方案(在这种情况下)......

if @term_type_id is NULL SELECT @term_type_id=-1

SELECT      [date],value FROM   history 
WHERE       id=@id 
AND         data_type_id=@data_type_id
AND         quote_type_id=@quote_type_id 
AND         update_type_id=@update_type_id
AND         ISNULL(term_type_id,-1)=@term_type_id
AND         source_id=@source_id
AND         ([date]>=@temp_from_date and [date]<=@temp_to_date)
ORDER BY    [date]

这适用于这种情况,因为term_type_id是身份(1,1)的结果,因此不能为-1。

答案 4 :(得分:0)

如果它是搜索条件中唯一可以为空的列,最好的方法是在单个UNION语句中拆分条件:

select date, value from dbo.History
where term_type_id is null
  -- Remaining search criteria
  and ...
union all
select date, value from dbo.History
where term_type_id = @term_type_id
  -- Remaining search criteria
  and ...

这是您可能的最快代码,主要是因为SQL Server对OR条件没有特别的诀窍。但是,另一个可以为空的列将把它变成一个相当不愉快的混乱。

如果您认为自己可以牺牲性能,那么T-SQL中有一个非常有用的功能 - NULLIF()

select date, value from dbo.History
where nullif(@term_type_id, term_type_id) is null
  -- Remaining search criteria
  and ...

然而,这种情况很可能是非SARGable。另请注意,参数的顺序在NULLIF()中很重要。或者,您可以设计各种复杂度的CASE构造,这些构造可能在语义上更适合您的确切要求。