CTE的周累计没有达到预期

时间:2021-04-09 09:33:29

I have this USERS table with users that can be of two different types (A and B). I need to show a report with the aggregate per type for each week. The query I have so far works well except some weeks are not grouping properly. In the example below, the week starting Jan 28th should have one line, not two.

我有这个用户表,其中的用户可以是两种不同的类型(A和B)。到目前为止,我的查询运行良好,只是有几个星期没有正确分组。在下面的例子中,从1月28日开始的一周应该有一行,而不是两条。

Week Starts |Week| Type A | Type B
------------+----+--------+------
2013-02-04  | 14 |  2     | 26
2013-01-28  | 13 |  5     | 191
2013-01-28  | 13 |  0     | 24
2013-01-21  | 12 |  1     | 134
2013-01-21  | 12 |  0     | 20
2013-01-14  | 11 |  1     | 143
2013-01-14  | 11 |  0     | 2
2013-01-07  | 10 |  0     | 233
2013-01-07  | 10 |  0     | 23
2012-12-31  | 9  |  0     | 12
2012-12-31  | 9  |  4     | 164
2012-12-31  | 9  |  0     | 20

SQL

SQL

;with cte as
(
select DATEADD(m,-3,GETDATE()) firstday, DATEADD(m,-3,GETDATE()) + 6 - DATEDIFF(day, 0, DATEADD(m,-3,GETDATE())) %7 lastday,  1 week
union all
select lastday + 1, case when GETDATE() < lastday + 7 then GETDATE() else lastday + 7 end,  week + 1
from cte
where lastday < GETDATE()
)
SELECT
    cast(firstday as date) 'Week Starts',
    cte.week as 'Week',
    Sum(CASE WHEN USR_TYPE = 'A' THEN 1 ELSE 0 END) As 'Type A',
    Sum(CASE WHEN USR_TYPE = 'B' THEN 1 ELSE 0 END) As 'Type B'
FROM cte left join USERS
ON cte.firstday <= USERS.CREATED
AND cte.lastday > USERS.CREATED
GROUP BY cte.week, cte.firstday, cte.lastday, DATEPART(YEAR,USERS.CREATED), DATEPART(wk,USERS.CREATED)
ORDER BY week desc

What am I doing wrong?

我做错了什么?

1 个解决方案

#1


5  

Without seeing any data from your users table I am going to take a guess.

在没有从用户表中看到任何数据的情况下,我将进行猜测。

The list of dates you are generating in the CTE includes the time.

在CTE中生成的日期列表包括时间。

You might need to cast() your firstday and lastday values as either a date or generate the list with no time.

您可能需要将第一天和最后一天的值转换为日期,或者在没有时间的情况下生成列表。

See a SQL Fiddle Demo

参见SQL小提琴演示。

Sample from your CTE and the new dates cast:

从你的CTE和新的日期铸造样品:

| CASTFIRSTDAY | CASTLASTDAY | WEEK |                        FIRSTDAY |                         LASTDAY |
---------------------------------------------------------------------------------------------------------
|   2012-11-05 |  2012-11-11 |    1 | November, 05 2012 20:08:10+0000 | November, 11 2012 20:08:10+0000 |
|   2012-11-12 |  2012-11-18 |    2 | November, 12 2012 20:08:10+0000 | November, 18 2012 20:08:10+0000 |
|   2012-11-19 |  2012-11-25 |    3 | November, 19 2012 20:08:10+0000 | November, 25 2012 20:08:10+0000 |
|   2012-11-26 |  2012-12-02 |    4 | November, 26 2012 20:08:10+0000 | December, 02 2012 20:08:10+0000 |
|   2012-12-03 |  2012-12-09 |    5 | December, 03 2012 20:08:10+0000 | December, 09 2012 20:08:10+0000 |
|   2012-12-10 |  2012-12-16 |    6 | December, 10 2012 20:08:10+0000 | December, 16 2012 20:08:10+0000 |

You might want to edit your CTE to return the date only values:

您可能想要编辑CTE以返回日期值:

;with cte as
(
    select 
        cast(DATEADD(m,-3,GETDATE()) as date) firstday, 
        cast(DATEADD(m,-3,GETDATE()) + 6 - DATEDIFF(day, 0, DATEADD(m,-3,GETDATE())) %7 as DATE) lastday,  
        1 week
    union all
    select 
        cast(DATEADD(DAY, 1, lastday) as date), 
        case 
            when cast(GETDATE() as date) < cast(DATEADD(DAY, 7, lastday) as date)
            then cast(GETDATE() as date) 
            else cast(DATEADD(DAY, 7, lastday) as date)
        end,  
        week + 1
    from cte
    where cast(lastday as date)  < cast(GETDATE() as date) 
)
select *
from cte

See SQL Fiddle with Demo

参见SQL小提琴演示

#1


5  

Without seeing any data from your users table I am going to take a guess.

在没有从用户表中看到任何数据的情况下,我将进行猜测。

The list of dates you are generating in the CTE includes the time.

在CTE中生成的日期列表包括时间。

You might need to cast() your firstday and lastday values as either a date or generate the list with no time.

您可能需要将第一天和最后一天的值转换为日期,或者在没有时间的情况下生成列表。

See a SQL Fiddle Demo

参见SQL小提琴演示。

Sample from your CTE and the new dates cast:

从你的CTE和新的日期铸造样品:

| CASTFIRSTDAY | CASTLASTDAY | WEEK |                        FIRSTDAY |                         LASTDAY |
---------------------------------------------------------------------------------------------------------
|   2012-11-05 |  2012-11-11 |    1 | November, 05 2012 20:08:10+0000 | November, 11 2012 20:08:10+0000 |
|   2012-11-12 |  2012-11-18 |    2 | November, 12 2012 20:08:10+0000 | November, 18 2012 20:08:10+0000 |
|   2012-11-19 |  2012-11-25 |    3 | November, 19 2012 20:08:10+0000 | November, 25 2012 20:08:10+0000 |
|   2012-11-26 |  2012-12-02 |    4 | November, 26 2012 20:08:10+0000 | December, 02 2012 20:08:10+0000 |
|   2012-12-03 |  2012-12-09 |    5 | December, 03 2012 20:08:10+0000 | December, 09 2012 20:08:10+0000 |
|   2012-12-10 |  2012-12-16 |    6 | December, 10 2012 20:08:10+0000 | December, 16 2012 20:08:10+0000 |

You might want to edit your CTE to return the date only values:

您可能想要编辑CTE以返回日期值:

;with cte as
(
    select 
        cast(DATEADD(m,-3,GETDATE()) as date) firstday, 
        cast(DATEADD(m,-3,GETDATE()) + 6 - DATEDIFF(day, 0, DATEADD(m,-3,GETDATE())) %7 as DATE) lastday,  
        1 week
    union all
    select 
        cast(DATEADD(DAY, 1, lastday) as date), 
        case 
            when cast(GETDATE() as date) < cast(DATEADD(DAY, 7, lastday) as date)
            then cast(GETDATE() as date) 
            else cast(DATEADD(DAY, 7, lastday) as date)
        end,  
        week + 1
    from cte
    where cast(lastday as date)  < cast(GETDATE() as date) 
)
select *
from cte

See SQL Fiddle with Demo

参见SQL小提琴演示