将日期范围拆分为几个月(使用 CTE)

Split date range into months (Using CTE)(将日期范围拆分为几个月(使用 CTE))
本文介绍了将日期范围拆分为几个月(使用 CTE)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个查询,我想要一个不使用递归 CTE 的替代查询.任何人都可以编辑和更新查询

I have this query and I want an alternative for this query without using recursive CTE. Can Anybody please edit and update the query

DECLARE @d TABLE(value int ,from_date DATE, to_date DATE);
INSERT @d VALUES (7,'2013-11-05','2013-11-25'),(8,'2013-07-05','2013-12-25'),(7,'2013-02-07','2013-04-14');
WITH cte AS
(SELECT value,from_date
      , to_date
      , from_date AS mo_from_date
      , DATEADD(day, day(from_date)* -1 + 1, from_date) AS bom_date
   FROM @d
UNION ALL
SELECT value, from_date
     , to_date
     , DATEADD(month,1,bom_date)
     , DATEADD(month,1,bom_date)
  FROM cte
 where DATEADD(month,1,mo_from_date) < to_date
)
SELECT value,mo_from_date
     , CASE when to_date < DATEADD(month,1,bom_date) THEN
           to_date
       ELSE
           DATEADD(day, -1, DATEADD(month,1,bom_date))
       END AS mo_to_date
  FROM cte


输出:

value   mo_from_date    mo_to_date
7   2013-11-05  2013-11-25
8   2013-07-05  2013-07-31
8   2013-08-01  2013-08-31
8   2013-09-01  2013-09-30
8   2013-10-01  2013-10-31
8   2013-11-01  2013-11-30
8   2013-12-01  2013-12-25
9   2013-02-07  2013-02-28
10  2013-03-01  2013-03-31
11  2013-04-01  2013-04-14

我尝试了以下查询,但它不起作用,任何人都可以更新此查询

I have tried below query but its not working,can anybody update this query

;with MonthList as (
    select 
        DATEADD(month, M, '12/1/1899') as 'FirstDay',
        dateadd(day, -1, dateadd(month, M + 1, '12/1/1899')) as 'LastDay',
        DATEADD(month, M + 1, '12/1/1899') as 'FirstDayNextMonth'
    from (
        select top 3000 ROW_NUMBER() over (order by s.name) as 'M'
        from master..spt_values s) s
)

select
   t.value, ml.FirstDay as from_date, ml.LastDay as to_date
from
    @d t
    inner join MonthList ml
        on  t.from_date < ml.FirstDayNextMonth
            and t.to_date >= ml.FirstDay

推荐答案

这是一种使用内联计数的方法:

This is a method using an inline tally:

DECLARE @d TABLE(value int ,from_date DATE, to_date DATE);
INSERT @d VALUES (7,'2013-11-25','2013-11-05'),(8,'2013-07-25','2013-12-05');

WITH N AS(
    SELECT N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
    SELECT 0 AS I
    UNION ALL
    SELECT TOP (SELECT MAX(DATEDIFF(MONTH,from_date,to_date)) FROM @d)
           ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
    FROM N N1, N N2) --100 months, add more cross joins for more months
SELECT d.[value],
       CASE WHEN DATEADD(DAY,1,EOMONTH(DATEADD(MONTH,T.I,d.from_date),-1)) < d.from_date THEN d.from_date ELSE DATEADD(DAY,1,EOMONTH(DATEADD(MONTH,T.I,d.from_date),-1)) END AS mo_from_date,
       CASE WHEN EOMONTH(DATEADD(MONTH,T.I,d.from_date)) > d.to_date THEN d.to_date ELSE DATEADD(MONTH,T.I,d.from_date) END AS mo_to_date 
FROM @d d
     JOIN Tally T ON DATEDIFF(MONTH,from_date,to_date) >= T.I;

不过,我个人建议你给自己一个日历表,那么问题就简单多了:

I do, personally, however, suggest you get yourself a Calendar Table, then the problem is far more simple:

SELECT d.[value],
       CASE WHEN d.from_date > MIN(CT.CalendarDate) THEN d.from_date ELSE MIN(CT.CalendarDate) END AS mo_from_date,
       CASE WHEN d.to_date < MAX(CT.CalendarDate) THEN d.to_date ELSE MAX(CT.CalendarDate) END AS mo_to_date
FROM @d d
     JOIN dbo.CalendarTable CT ON d.from_date <= CT.CalendarDate --To assumes that the to_date being before the
                              AND d.to_date >= CT.CalendarDate   --the from date is an error.
GROUP BY d.[value],
         d.from_date,
         d.to_date,
         MONTH(CT.CalendarDate),
         YEAR(CT.CalendarDate);

两种解决方案都假设 from 日期应该在 to 日期之前之前;即使它在您的数据中似乎不正确.如果您的 from 日期可以是 after 您的 to 日期,我建议您有数据问题,因为如何开始strong> 之后结束?

Both solutions assume that the from date should be before the to date though; even though that it appears to not be true in your data. If your from date can be after your to date, I would suggest you have data issues, as how can something start after it has ended?

这篇关于将日期范围拆分为几个月(使用 CTE)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Execute complex raw SQL query in EF6(在EF6中执行复杂的原始SQL查询)
Hibernate reactive No Vert.x context active in aws rds(AWS RDS中的休眠反应性非Vert.x上下文处于活动状态)
Bulk insert with mysql2 and NodeJs throws 500(使用mysql2和NodeJS的大容量插入抛出500)
Flask + PyMySQL giving error no attribute #39;settimeout#39;(FlASK+PyMySQL给出错误,没有属性#39;setTimeout#39;)
auto_increment column for a group of rows?(一组行的AUTO_INCREMENT列?)
Sort by ID DESC(按ID代码排序)