【问题标题】:Filtering multiple dates in row with optional to and from parameters使用可选的 to 和 from 参数过滤行中的多个日期
【发布时间】:2014-08-30 01:56:35
【问题描述】:

我有一张包含三个日期的表格:

id        date1        date2        date3
1         1945-12-13   1930-11-04   null
2         1970-09-12   1971-09-13   1972-09-14
3         null         null         null
4         2000-01-01   2001-01-01   2002-01-01

我的 proc 传入 2 个参数:

@dateFrom datetime = NULL,
@dateTo datetime = NULL  

我想返回介于两者之间的任何日期的记录。 @dateFrom 或 @DateTo 的 NULL 使其开放结束。

这适用于开放式的情况,但不适用于两者都不为空的情况。

SELECT * 
FROM Table1
WHERE (@dateFrom IS NULL 
          OR ISNULL(date1,'12/31/1753') >= @dateFrom
          OR ISNULL(date2,'12/31/1753') >= @dateFrom 
          OR ISNULL(date3,'12/31/1753') >= @dateFrom)
  AND (@dateTo IS NULL 
          OR  ISNULL(date1,'12/31/2099') <= @dateTo
          OR ISNULL(date2,'12/31/2099') <= @dateTo
          OR ISNULL(date3,'12/31/2099') <= @dateTo)

如果我通过 @dateFrom = '1940-01-01' 和 @dateTo = '1950-01-01', 我只想要第一条记录,但我得到了 1、2 和 4,因为它们的日期都 > 1940。

我只是想不通如何构建它。

已更改列名和表名以保护无辜者。

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    您需要在范围内单独过滤每个日期字段,如下所示:

    WHERE 
       (Date1 >= ISNULL(@DateFrom,'17531231')
        AND Date1 <= ISNULL(@dateTo,'20991231'))
    OR
     (Date2 >= ISNULL(@DateFrom,'1753-12-31')
        AND Date2 <= ISNULL(@dateTo,'20991231'))
    OR
     (Date3 >= ISNULL(@DateFrom,'1753-12-31')
        AND Date3 <= ISNULL(@dateTo,'20991231'))
    

    否则,您不会检查每个日期字段的范围,只是该行中的日期与条件之一匹配。

    【讨论】:

    • 在日期更改为 'YYYYMMDD' 之前我拒绝对此进行投票
    • @Lamak 为您修复
    • 谢谢!,现在我可以投票了(我的意思是,假设列的数据类型是DATE 而不是DATETIME
    • @JNK 伙计!你刚刚度过了我的周末。
    • @Moose 如果您的列是DATETIME,那么这可能根据您的语言配置起作用,但可能不适用于某些用户。明确的做法是使用 'YYYYMMDD' 而不使用 -
    【解决方案2】:

    只是换一种方式来看待它。这个解决方案也可以。它以额外的代码块和连接为代价使 where 子句更简单。

    CREATE TABLE #dates (id INT, date1 DATE, date2 DATE, date3 DATE)
    
    INSERT INTO #dates 
    VALUES
    ('1','12/13/1945','11/4/1930',NULL),
    ('2','9/12/1970','9/13/1971','9/14/1972'),
    ('3',NULL,NULL,NULL),
    ('4','1/1/2000','1/1/2001','1/1/2002')
    
    DECLARE
        @dateFrom datetime = '1940-01-01',
        @dateTo datetime = '1950-01-01'
    
    ;WITH dateFilter AS (
    
    SELECT id,[Date],DateIndex
    FROM
    (SELECT
    id, date1, date2, date3
    FROM #dates) p
    UNPIVOT([DATE] FOR DateIndex IN ([date1],[date2],[date3])) AS up
    WHERE
        up.[DATE] BETWEEN @dateFrom AND @dateTo
    )
    
    SELECT
        d.*
    FROM #dates d
    INNER JOIN dateFilter df
    ON df.id = d.id
    
    
    DROP TABLE #dates
    

    【讨论】:

    • 这是一个关于 UNPIVOT 的很棒的教程,谢谢!
    【解决方案3】:

    好的,这很简单,但我认为它会起作用,因为它在一个过程中......

    声明@startDate datetimne 声明@enddate 日期时间

    如果 @datefrom 为 NULL 设置@startDate = '12/31/1753' 别的 设置@startDate = @datefrom

    如果 @dateTo 为 NULL 设置@endDate = '12/31/2099' 别的 设置@endDate = @dateto

    并使用@datefrom 和@dateto 来限定...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-13
      • 2012-12-25
      • 1970-01-01
      • 2014-05-07
      相关资源
      最近更新 更多