将日期范围拆分为SQL Server 2005上的年月行

时间:2015-12-18 15:00:19

标签: sql sql-server sql-server-2005

我需要创建一个输出,我每年有一行。

假设数据集是:

id |        dateStart        |        dateEnd
1  | 2015-01-01 00:00:00.000 | 2015-03-31 00:00:00.000
2  | 2014-07-01 00:00:00.000 | 2014-08-31 00:00:00.000
...

我需要以下输出:

id | year-month
1  |  2015-01
1  |  2015-02
1  |  2015-03
2  |  2014-07
2  |  2014-08

输出可以是任何数据类型,因为我可以稍后更改它。 那是2015-01,以下是好的,“2015-01-01 00:00:00.000”,“2015-01-01”,“201501”,“2015 | jan”等。

注意我正在使用SQL Server 2005。

3 个答案:

答案 0 :(得分:1)

这是一个使用递归CTE的方法:

with CTE as (
      select id, dateStart as dte, dateEnd
      from t
      union all
      select id, dateadd(month, 1, dte), dateEnd
      from CTE
      where dateadd(month, 1, dte) < dateEnd
     )
select id, dte
from CTE;

您可以将最终结果转换为您喜欢的任何格式。例如:

select id, year(dte) * 10000 + month(dte) as yyyymm_int

select id, cast(year(dte) * 10000 + month(dte) as varchar(255)) as yyyymm

答案 1 :(得分:1)

生成计数表(只需确保在那里获得足够的行)。计数器将包含值0,1,2,.....n。然后,您使用条件将此值添加为startDate的月份,直到它大于endDate

DECLARE @t TABLE
    (
      id INT ,
      dateStart DATETIME ,
      dateEnd DATETIME
    )
INSERT  INTO @t
VALUES  ( 1, '2015-01-01 00:00:00.000', '2015-03-31 00:00:00.000' ),
        ( 2, '2014-07-01 00:00:00.000', '2014-08-31 00:00:00.000' )

;WITH cte AS(SELECT -1 + ROW_NUMBER() OVER(ORDER BY t1.m) m 
             FROM(VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0))t1(m) CROSS JOIN 
                 (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0))t2(m)) 
SELECT t.id, 
       DATEADD(mm, c.m, t.dateStart) AS year_month 
FROM cte c
JOIN @t t ON DATEADD(mm, c.m, t.dateStart) <= t.dateEnd
ORDER BY t.id, year_month

输出:

id  year_month
1   2015-01-01 00:00:00.000
1   2015-02-01 00:00:00.000
1   2015-03-01 00:00:00.000
2   2014-07-01 00:00:00.000
2   2014-08-01 00:00:00.000

答案 2 :(得分:1)

在一个理想的世界中,你会有calendar table,那么你的查询就是:

SELECT  t.id,
        c.FirstDayOfMonth
FROM    YourTable AS t
        INNER JOIN dbo.Calendar c
            ON c.FirstDayOfMonth >= t.DateStart
            AND c.FirstDayOfMonth <= t.DateEnd
            AND c.DayOfMonth = 1;

假设您没有日历表,那么您可以使用动态生成的数字列表(阅读this article了解更多信息)。以下将生成1-10,000的列表:

WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N3.N) FROM N3)
SELECT * FROM Numbers;

然后您可以将其加入原始表格:

DECLARE @T TABLE (id INT, DateStart DATE, DateEnd DATE);
INSERT @T (ID, DateStart, DateEnd)
VALUES (1, '20150101', '20150331'), (2, '20140701', '20140831');

WITH N1 AS (SELECT N FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N (N)),
N2 (N) AS (SELECT 1 FROM N1 AS N1 CROSS JOIN N1 AS N2),
N3 (N) AS (SELECT 1 FROM N2 AS N1 CROSS JOIN N2 AS N2),
Numbers (Number) AS (SELECT ROW_NUMBER() OVER(ORDER BY N3.N) FROM N3)

SELECT  t.ID,
        [year-month] = DATEADD(MONTH, n.Number + DATEDIFF(MONTH, 0, t.DateStart), 0)
FROM    @T AS t
        INNER JOIN Numbers AS N
            ON N.Number - 1 <= DATEDIFF(MONTH, t.DateStart, t.DateEnd);