有趣的SQL加入日期之间的日期

时间:2011-08-18 18:00:09

标签: sql sql-server-2005 sql-server-2008 datetime join

首先,感谢帮助我解决这个问题的任何人。我正在使用SQL 2005,但如果05中没有可用的解决方案,则可以使用2008。

我有一行看起来像这样的数据:

select * from mySPtable

| myPK | Area | RequestType |  StartDate  |  EndDate  |
   1      SB        ADD        8/14/2011    8/18/2011
   2      NB        RMV        8/16/2011    8/16/2011

所以我想做的是按天计算每个区域的总请求数。结果应该是:

|  myDate  | RequestType |  Area  | myCount |
  8/14/2011      ADD         SB        1
  8/15/2011      ADD         SB        1
  8/16/2011      ADD         SB        1
  8/16/2011      RMV         NB        1
  8/17/2011      ADD         SB        1
  8/18/2011      ADD         SB        1

我该怎么做呢?我很难过,没有任何谷歌搜索帮助。

3 个答案:

答案 0 :(得分:10)

您需要一个日历表,或者您可以使用CTE生成一个。一旦你有了,那么查询的其余部分应该是相当简单的。由于递归问题而且不允许使用聚合,CTE方法可能有点复杂,所以下面我使用了表变量。您还可以将其保存为数据库中的永久表。

SET NOCOUNT ON

DECLARE @Calendar TABLE (my_date DATETIME NOT NULL)
DECLARE @date DATETIME, @max_date DATETIME

SELECT @date = MIN(StartDate), @max_date = MAX(EndDate) FROM My_Table

WHILE (@date <= @max_date)
BEGIN
    INSERT INTO @Calendar (my_date) VALUES (@date)
    SELECT @date = DATEADD(dy, 1, @date)
END

SELECT
    C.myDate,
    M.RequestType,
    M.Area,
    COUNT(*) AS myCount
FROM
    @Calendar C
INNER JOIN My_Table M ON
    M.StartDate <= C.myDate AND
    M.EndDate >= C.myDate
GROUP BY
    C.myDate,
    M.RequestType,
    M.Area
ORDER BY
    C.myDate,
    M.RequestType,
    M.Area

根据潜在日期范围的大小,填写表变量可能需要一段时间。例如,如果范围跨越十年或两年。

答案 1 :(得分:3)

听起来你可能需要'Calendar' file。特别是作为一个大型企业组织的一部分,这将变得非常有用。

生成日历后,您可以使用以下内容获取表格:

SELECT a.isoDate, b.RequestType, b.Area, count(*)
FROM calendar as a
JOIN mySPTable as b
ON a.isoDate between b.StartDate and b.EndDate
WHERE a.isoDate >= [input_start_date] 
      AND a.isoDate < [input_end_date]
GROUP BY a.isoDate, b.RequestType, b.Area

这将为日历文件中的每个日期生成一行,该行位于mySPTable的至少一行的开始日期和结束日期之间。

作为旁注,也可以使用递归CTE生成日期范围,但特别是从长远来看,我建议生成并使用日历文件。
快速CTE:

WITH DateRange (thisDate) as (SELECT [input_start_date]
                              UNION ALL
                              SELECT DATEADD(dy, 1, thisDate)
                              FROM DateRange
                              WHERE thisDate < [input_end_date])

答案 2 :(得分:2)

您可以使用数字表(从0开始)执行此操作。这里我使用master..spt_values代替。 SQL, Auxiliary table of numbers

select dateadd(day, N.Number, M.StartDate) as myDate,
       RequestType,
       Area, 
       count(*) as myCount
from mySPtable as M
  inner join master..spt_values as N
    on N.Number <= datediff(day, M.StartDate, M.EndDate)
where N.type = 'P'
group by dateadd(day, N.Number, M.StartDate),
         RequestType,
         Area
order by dateadd(day, N.Number, M.StartDate)