T-SQL范围内的所有事件

时间:2016-04-07 12:59:26

标签: sql sql-server

之前可能已经提出并回答了这个问题,但是我甚至难以将其作为一个问题(因此标题)来表达。

我有一个数据库表,基本上是

[EventId] INT,
[FirstOccurance_Month] DATETIME,
[LastOccurance_Month] DATETIME

有一些类似的数据:

[EventId] [FirstOccurance_Month] [LastOccurance_Month]
1         2015-11-01             2016-01-01
2         2015-12-01             2016-03-01
3         2016-02-01             2016-02-01

我想要实现的是一个SQL语句,它将EventId作为一列输出,并将其作为第二列发生的所有月份输出。所以对于上面的数据,它看起来像这样:

[EventId] [Month]
1         2015-11-01
1         2015-12-01
1         2016-01-01
2         2015-12-01
2         2016-01-01
2         2016-02-01
2         2016-03-01
3         2016-02-01

我有一种感觉它会涉及CROSS APPLY,所以我要找出实际上是什么......

3 个答案:

答案 0 :(得分:3)

您可以使用Tally表执行此任务:

;WITH Tally AS (
  SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS i
  FROM (VALUES (0), (0), (0), (0), (0)) AS t1(n)
  CROSS JOIN (VALUES (0), (0), (0), (0), (0)) AS t2(n)
)
SELECT m.EventId, DATEADD(m, t.i, FirstOccurance_Month) AS [Month]
FROM Tally AS t
INNER JOIN mytable AS m
ON DATEADD(m, t.i, FirstOccurance_Month) <= LastOccurance_Month
ORDER BY m.EventId

上述查询使用的Tally表包含25行。您可以轻松调整它以满足您的实际需求。

Demo here

答案 1 :(得分:1)

一种方法是使用递归CTE

; with rcte as
(
    select  EventId, [Month] = FirstOccurance_Month
    from    yourtable 

    union all

    select  t.EventId, [Month] = dateadd(month, 1, r.[Month])
    from    rcte r
            inner join yourtable  t on  r.EventId   = t.EventId
    where   r.[Month]   < t.LastOccurance_Month 
)
select  *
from    rcte

答案 2 :(得分:0)

为了完整起见,这是最终的解决方案。我还在调查接受的答案到底在做什么,它看起来比我的好......

DECLARE @startDate DATETIME = DATEADD(MONTH,-1,(SELECT MIN(DATEADD(MONTH, DATEDIFF(MONTH, 0, [FirstOccurance_Month]), 0)) FROM LogTable))
DECLARE @endDate  DATETIME = (SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))

SELECT * FROM 
(
    SELECT DATEADD(MONTH, num, firstdate) AS [DateTime] FROM
    (
        SELECT a.[num] FROM
        (
            SELECT ROW_NUMBER() OVER (PARTITION BY NULL ORDER BY (SELECT NULL)) AS num 
           FROM BigDataBase.Information_Schema.Columns c
        )a 
        WHERE [num] < 
        (
            SELECT DATEDIFF(MONTH,@startDate,@endDate) b
        ) 
    ) n 
    CROSS JOIN
    (
        SELECT @startDate firstdate
    ) b
) a INNER JOIN
(
    SELECT  [EventId],[FirstOccurance_Month],[LastOccurance_Month]
    FROM    LogTable 
) b
ON  a.[DateTime] >= DATEADD(MONTH, DATEDIFF(MONTH, 0, b.[FirstOccurance_Month]), 0)  
AND a.[DateTime] <= DATEADD(MONTH, DATEDIFF(MONTH, 0, b.[LastOccurance_Month]), 0)
ORDER BY b.[EventId],a.[DateTime]