SQL按月分割

时间:2015-11-03 22:13:04

标签: sql sql-server tsql common-table-expression

下午好, 我看起来似乎是一个简单的问题,事实证明并非如此简单。我有2个约会。 BeginPeriod(2010-06-10)和EndPeriod(2011-06-11)。

如果这些日期可以分解为各自的每月分类,我希望看到什么。对于上面的示例,如

  • 2010/06/10 - 2010/06/30
  • 2010/07/01 - 2010/07/31
  • 2010/08/01 - 2010/08/31
  • ............
  • 2011/06/01 - 2011/06/10

我不是特别关心这个方法。 CTE很好,但不是首选。正如他们所说,乞丐不能成为选择者。

一切顺利, 乔治

2 个答案:

答案 0 :(得分:6)

CTE是。

DECLARE @BeginPeriod DATETIME = '2010-06-10',
        @EndPeriod DATETIME = '2011-06-11'

;WITH cte AS
(
    SELECT DATEADD(month, DATEDIFF(month, 0, @BeginPeriod), 0) AS StartOfMonth, 
           DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, @BeginPeriod) + 1, 0)) AS EndOfMonth
    UNION ALL
    SELECT DATEADD(month, 1, StartOfMonth) AS StartOfMonth, 
           DATEADD(s, -1, DATEADD(mm, DATEDIFF(m, 0, DATEADD(month, 1, StartOfMonth)) + 1, 0)) AS EndOfMonth  
    FROM   cte
    WHERE  DATEADD(month, 1, StartOfMonth) <= @EndPeriod
)
SELECT  
    (CASE WHEN StartOfMonth < @BeginPeriod THEN @BeginPeriod ELSE StartOfMonth END) StartOfMonth,
    (CASE WHEN EndOfMonth > @EndPeriod THEN @EndPeriod ELSE EndOfMonth END) EndOfMonth
FROM cte

最后EndOfMonth是您用作@EndPeriod的值,如果您想要前一天将其设置为DATEADD(day, -1, @EndPeriod)

您可以使用它来缩短时间。

SELECT  
    CONVERT(VARCHAR(10), (CASE WHEN StartOfMonth < @BeginPeriod THEN @BeginPeriod ELSE StartOfMonth END), 120) StartOfMonth,
    CONVERT(VARCHAR(10), (CASE WHEN EndOfMonth > @EndPeriod THEN @EndPeriod ELSE EndOfMonth END), 120) EndOfMonth
FROM cte

答案 1 :(得分:0)

“数字”CTE的另一个选项

declare @df datetime, @dt datetime
set @df = '20100610'
set @dt = '20110611'

;WITH e1(n) AS
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT ROW_NUMBER() OVER (ORDER BY e1.n) FROM e1 CROSS JOIN e1 AS b) -- 10*10
select  
    case when e2.n = 1 
        then @df 
        else dateadd(day, -day(@df) + 1, dateadd(month, e2.n - 1, @df)) end, 
    case when e2.n = datediff(month, @df, @dt) + 1 
        then dateadd(month, e2.n -1 , @df) 
        else EOMONTH( dateadd(month, e2.n -1 , @df) ) end
from e2
where e2.n 

您可以使用其他选项代替Numbers CTE,例如此处所述 http://sqlperformance.com/2013/01/t-sql-queries/generate-a-set-1 我经常在我的数据库中有Numbers表来完成这些任务。我认为主要是因为我在将CTE添加到MS SQL之前开始使用这种技术,但它的输入也较少。