下午好, 我看起来似乎是一个简单的问题,事实证明并非如此简单。我有2个约会。 BeginPeriod(2010-06-10)和EndPeriod(2011-06-11)。
如果这些日期可以分解为各自的每月分类,我希望看到什么。对于上面的示例,如
我不是特别关心这个方法。 CTE很好,但不是首选。正如他们所说,乞丐不能成为选择者。
一切顺利, 乔治
答案 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之前开始使用这种技术,但它的输入也较少。