【问题标题】:A single sql query which can handle both null or valued date range in sql server可以在 sql server 中处理空日期范围或有值日期范围的单个 sql 查询
【发布时间】:2009-10-05 15:22:51
【问题描述】:

使用 SQL Server 2008。我有一个存储过程,它具有开始和结束日期作为日期范围的输入参数。

寻找一个 single sql 查询,该查询在 where 子句中具有介于开始和结束日期之间的日期,该查询可以处理日期为空或都有值的两种情况。

我不想使用 IF 语句。

【问题讨论】:

  • 请问您的查询在定义两个参数后会是什么样子?

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


【解决方案1】:
WITH    limits AS
        (
        SELECT  COALESCE(@startDate, MIN(mydate)) AS startDate, COALESCE(@endDate, MAX(mydate)) AS endDate
        FROM    mytable
        )
SELECT  m.*
FROM    limits
JOIN    mytable m
ON      mydate BETWEEN startDate AND endDate

如果mydate 上有索引,这将是最有效的,因为此条件是可搜索的,并且将使用Index Seek

如果没有索引,则使用别人提出的IFNULL构造。

【讨论】:

  • 不错。我喜欢将日期范围限制为表格中已有的内容。
  • 小心:在没有好的日期索引(用户没有明确指定)的情况下,min/max() 调用代价高昂
  • 尽管我讨厌投反对票,但假设存在索引,这似乎是最好的。 +1
  • wcm - 你投反对票的不是自己,而是帮助推动正确答案越过终点线。确实,积分并没有太大的意义,而且您对积分的担心越少,您就会越开心。
【解决方案2】:

你可以这样做:

SELECT blah
FROM MyTable
WHERE 
    (@startDate IS NULL OR MyTable.StartDate >= @startDate)
    AND (@endDate IS NULL OR MyTable.EndDate <= @endDate)

但是请注意,像这样的 AND 子句中的大量参数可能会导致错误地缓存查询计划。 SO上有很多关于不正确的查询计划和参数“嗅探”的问题。

【讨论】:

    【解决方案3】:

    Quassnoi 的答案可能是最好的,但这是另一种看法:

    SELECT *
    FROM MyTable
    WHERE 
        MyTable.StartDate >= ISNULL(@startDate, MyTable.StartDate)
        AND MyTable.EndDate <= ISNULL(@startDate, MyTable.EndDate)
    

    【讨论】:

    • 当心这会阻止索引的使用。
    • 我认为这更容易阅读,但我认为递归是正确的。
    • +1 - 有用但递归对索引很有帮助。
    【解决方案4】:
    SELECT *
    FROM MyTable
    WHERE 
         MyTable.StartDate >= COALESCE(MyTable.StartDate, "1/1/1900") 
         /* Date selected as earliest plausible constant to avoid min() lookup */
    
     AND MyTable.EndDate <= COALESCE(MyTable.EndDate, "1/1/3001")
         /* Date selected as latest plausible constant to avoid max() lookup */
    

    显然,您需要为您的应用程序/域选择正确的常量。如果您没有足够宽但比从表中显式查找最小值/最大值要快得多的常量,这有点冒险,而且大多数应用程序/域都有定义良好的框架。

    【讨论】:

      【解决方案5】:
      SELECT
          Column1,....
          FROM MyTable
          WHERE MyTable.StartDate>=COALESCE(@startDate,CONVERT(datetime,'01/01/1753'))
              AND MyTable.EndDate<=COALESCE(@endDate,CONVERT(datetime,'12/31/9999'))
      

      另外,这里有一篇关于这个主题的非常全面的文章:

      Dynamic Search Conditions in T-SQL by Erland Sommarskog

      它涵盖了尝试编写具有多个可选搜索条件的查询的所有问题和方法

      这是目录:

         Introduction
            The Case Study: Searching Orders
            The Northgale Database
         Dynamic SQL
            Introduction
            Using sp_executesql
            Using the CLR
            Using EXEC()
            When Caching Is Not Really What You Want
         Static SQL
            Introduction
            x = @x OR @x IS NULL
            Using IF statements
            Umachandar's Bag of Tricks
            Using Temp Tables
            x = @x AND @x IS NOT NULL
            Handling Complex Conditions
         Hybrid Solutions – Using both Static and Dynamic SQL
            Using Views
            Using Inline Table Functions
         Conclusion
         Feedback and Acknowledgements
         Revision History
      

      【讨论】:

        【解决方案6】:

        你可以这样做

        SELECT blah
        FROM MyTable
        WHERE 
        1 = case 
                when @startDate IS NOT NULL then  MyTable.Date >= @startDate
            else 1 end
        AND
        1 = case 
                when @endDate IS NOT NULL then  MyTable.Date <= @endDate
            else 1 end
        

        SELECT blah
        FROM MyTable
        WHERE 
        (
            (@startDate is not null and @endDate is not null and MyTable.Date between @startDate and @endDate )
            or
            (@startDate is null and @endDate is null )
        )
        

        【讨论】:

          【解决方案7】:

          最大值:

          Case when @a > @b or @b is null then @a else @b end.
          

          这也处理空值。

          简单。

          【讨论】:

            猜你喜欢
            • 2016-12-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-01-11
            • 1970-01-01
            • 2014-12-06
            • 1970-01-01
            相关资源
            最近更新 更多