TSQL - 查询两个日期字段之间的日期列表

Posted

技术标签:

【中文标题】TSQL - 查询两个日期字段之间的日期列表【英文标题】:TSQL - Query a list of dates between two date fields 【发布时间】:2021-12-08 18:05:02 【问题描述】:

数据:

DECLARE @Dates TABLE
    (
        [MyDate]  DATE
      , [WkStart] DATE
      , [WkEnd]   DATE
    ) ;

INSERT INTO @Dates
SELECT  '2021-10-03'
      , '2021-09-27'
      , '2021-10-03'
UNION
SELECT  '2021-10-21'
      , '2021-10-18'
      , '2021-10-24'
UNION ALL
SELECT  '2021-10-23'
      , '2021-10-18'
      , '2021-10-24'
UNION
SELECT  '2021-10-27'
      , '2021-10-25'
      , '2021-10-31' ;

目标:

输出 2 个字段。第一个 = 日期字段,第二个 = 位字段。日期字段将包含每条记录的 [WkStart] 和 [WkEnd] 之间的所有日期。当 [MyDate] 等于第一个字段的值时,位字段将为真。桌子很大,所以性能很重要。当 2+ [MyDate] 值属于同一周范围时,该周的日期不应重复。

预期输出:

我的尝试:

; WITH recrCTE AS
    (
        SELECT  CAST ( [WkStart] AS DATETIME ) AS [DateVal]
              , [WkEnd]
              , [MyDate]
        FROM    @Dates
        UNION ALL
        SELECT  [DateVal] + 1
              , [WkEnd]
              , [MyDate]
        FROM    recrCTE
        WHERE   [DateVal] + 1 <= [WkEnd]
    )
SELECT  [DateVal]
      , IIF ( [MyDate] = [DateVal], 1, 0 ) AS [isMyDate]
FROM    recrCTE
ORDER BY [DateVal]
OPTION ( MAXRECURSION 0 ) ;

当前输出:

这个解决方案有两个明显的问题。 1st,记录在同一日期范围内(10 月 21 日和 10 月 23 日)内重复 2 个以上的日期。第二,这两个日期都以 2 个不同的位值重复,因此不能简单地使用 DISTINCT。我觉得可能成为问题的第三个问题是性能。也许有一种更有效的方法来实现这一点(也许使用函数)而不是使用递归 CTE。

【问题讨论】:

对于您的1st2nd 问题,一个快速的方法是执行GROUP BY DateValMAX(isMyDate)。为了提高性能,请使用计数表而不是递归 cte 一周内最多可以有 7 行,对吗?你说这个表很大,你是否需要对整个表每次运行查询,或者你是否会有比所有时间更小的日期范围的合理谓词>? 【参考方案1】:

一周只能有 7 天时不需要递归;只需将 7 个值硬编码为 1-7,这样您就可以使用这些值将集合从 WkStart 爆炸到 6 天后。然后您可以有条件地在DateVal 上聚合该输出。

;WITH alldays AS 
(
  SELECT DateVal = DATEADD(DAY, days.n-1, d.WkStart), 
         d.MyDate
  FROM @Dates AS d
  CROSS JOIN (VALUES(1),(2),(3),(4),(5),(6),(7)) AS days(n)
  -- if the table is large and performance is a concern, then:
  -- WHERE d.? -- some reasonable where clause belongs here?
)
SELECT DateVal, 
       IsMyDate = MAX(CASE MyDate WHEN DateVal THEN 1 ELSE 0 END)
FROM alldays 
GROUP BY DateVal
ORDER BY DateVal;
示例db<>fiddle

【讨论】:

谢谢亚伦!通过“大表”,我的意思是这个查询将成为可以跨越多年的报告过程的一部分,因此@Dates 可以变得很大(仍然少于 1K 记录)。无论如何,这是一个很好的解决方案。谢谢!!在阅读了 squirrel 的建议(也谢谢你)之后,我开始使用计数表类型的查询(双 CTE),虽然执行计划显示相同的成本,但您的执行计划更清洁。简单地交叉连接到 1-7 个值是有意义的。再次感谢!希望在未来的某个 SQL 星期六再次见到您。干杯! @007 没问题詹姆斯邦德! 为什么不;你只做0到6,那你就不需要-1 @Charlieface 好吧,根据我的经验,大多数来这里寻求帮助的人都不是基于 0 的思想家。 @007 这个周末开车去的时候看到的,很不错。

以上是关于TSQL - 查询两个日期字段之间的日期列表的主要内容,如果未能解决你的问题,请参考以下文章

如何在mysql选择查询中获取两个日期之间的日期列表[重复]

如何使用查询获取两个给定日期之间的月份列表?

使用函数获取两个日期之间的日期列表

如何在 MySQL 中的两个日期之间获取特定日期

SQL - 创建两个日期之间的自定义日期列表

查找表中的任何日期是不是在两个日期之间