SQL - 如何根据现有数据集中的日期范围为每个月生成行?

时间:2014-06-18 01:54:34

标签: sql-server sql-server-2012

假设我有一个数据集:

rowID |  dateStart  |   dateEnd  | Year | Month
121   | 2013-10-03  | 2013-12-03 | NULL | NULL
143   | 2013-12-11  | 2014-03-11 | NULL | NULL
322   | 2014-01-02  | 2014-02-11 | NULL | NULL

我希望sql根据dateStart和dateEnd生成以下数据源。请注意年份和月份分组。

rowID |  dateStart  |   dateEnd  | Year | Month
121   | 2013-10-03  | 2013-12-03 | 2013 |   10
121   | 2013-10-03  | 2013-12-03 | 2013 |   11
121   | 2013-10-03  | 2013-12-03 | 2013 |   12
143   | 2013-12-11  | 2014-03-11 | 2013 |   12
143   | 2013-12-11  | 2014-03-11 | 2014 |    1
143   | 2013-12-11  | 2014-03-11 | 2014 |    2
143   | 2013-12-11  | 2014-03-11 | 2014 |    3
322   | 2014-01-02  | 2014-02-11 | 2014 |    1
322   | 2014-01-02  | 2014-02-11 | 2014 |    2

我很难绕过这一个。有什么想法吗?

3 个答案:

答案 0 :(得分:10)

通过创建整数列表然后使用它来递增日期,我发现最容易解决这些问题。这是一个例子:

with nums as (
      select 0 as n
      union all
      select n + 1 as n
      from nums
      where n < 11
     )
select rowid, datestart, dateend,
       year(dateadd(month, n.n, datestart)) as yr,
       month(dateadd(month, n.n, datestart)) as mon
from table t join
     nums n
     on dateadd(month, n.n - 1, datestart) <= dateend;

答案 1 :(得分:1)

首先,创建一个带有2个日期的表值函数,并将年和月作为表格返回:

create function dbo.YearMonths(@StartDate DateTime, @EndDate DateTime)
returns @YearMonths table
([Year] int,
[Month] int)
as
begin

    set @EndDate = DATEADD(month, 1, @EndDate)
    while (@StartDate < @EndDate)
    begin

    insert into @YearMonths
    select YEAR(@StartDate), MONTH(@StartDate)  

    set @StartDate = DATEADD(month, 1, @StartDate)

    end

return
end

以下为例:

select *
from dbo.YearMonths('1/1/2014', '5/1/2014')

返回:

enter image description here

然后你会像这样加入它以获得你想要的东西:

select m.*, ym.Year, ym.Month
from myTable m
cross apply dbo.YearMonths(dateStart, dateEnd) ym

答案 2 :(得分:0)

试试这个:

declare @months table(mth int)
insert into @months values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)

declare @calendar table(yr int,mth int)
insert into @calendar
select distinct year(datestart),mth
from tbl cross join @months
union
select distinct year(dateend),mth
from tbl cross join @months

select t.rowID, t.datestart, t.dateend, y.yr [Year], y.mth [Month] 
from
yourtable t
inner join @calendar y on year(datestart) = yr or year(dateend) = yr
where 
(mth >= month(datestart) and mth <= month(dateend) and year(datestart) = year(dateend))
or 
(year(datestart) < year(dateend)) 
 and 
 (year(datestart) = yr and mth >= month(datestart) --All months of start year
 or 
 (year(dateend) = yr and mth <= month(dateend))) -- All months of end year
order by t.rowID, [Year],[Month]

我们创建了一个&#39;日历表&#39;其中列出了源表中存在的所有月份和年份组合。然后,我们根据年份将源表连接到日历表,并根据需要进行过滤。