繁体   English   中英

如何按定制周定义记录?

[英]How to group records per custom defined week?

我试图在SQL中编写一个将在MySQL中运行的报告。

我有一张companies表:

INSERT INTO companies
(`id`, `name`, `createdDate`)
VALUES
    (1, 'company_1', '2016-02-01 04:00:00'),
    (2, 'company_2', '2016-01-01 04:00:00'),
    (3, 'company_3', '2016-04-01 04:00:00'),
    (4, 'company_4', '2016-03-01 04:00:00'),
    (5, 'company_5', '2016-02-01 04:00:00')
;

我有一个users表,其中一群用户在一个公司到多个用户场景中为特定公司工作。 用户接受邀请加入公司,我们按如下方式获取日期:

INSERT INTO users
    (`userId`, `companyId`, `acceptedInviteDate`)
VALUES
    (1, 1, '2017-01-01 04:00:00'),
    (2, 1, '2017-01-02 04:00:00'),
    (3, 1, '2017-01-03 04:00:00'),
    (4, 1, '2017-01-04 04:00:00'),
    (5, 2, '2017-01-05 04:00:00'),
    (6, 2, '2017-01-09 04:00:00'),
    (7, 2, '2017-01-10 04:00:00'),
    (8, 2, '2017-01-11 04:00:00'),
    (9, 2, '2017-01-12 04:00:00'),
    (10, 3, '2017-01-13 04:00:00'),
    (11, 3, '2017-01-15 04:00:00'),
    (12, 3, '2017-01-02 04:00:00'),
    (13, 3, '2017-01-03 04:00:00'),
    (14, 3, '2017-01-04 04:00:00'),
    (15, 3, '2017-01-05 04:00:00'),
    (16, 3, '2017-01-06 04:00:00'),
    (17, 3, '2017-01-07 04:00:00'),
    (18, 3, '2017-01-08 04:00:00'),
    (19, 3, '2017-01-09 04:00:00'),
    (20, 3, '2017-01-11 04:00:00'),
    (21, 3, '2017-01-13 04:00:00'),
    (22, 3, '2017-01-15 04:00:00'),
    (23, 3, '2017-01-16 04:00:00'),
    (24, 3, '2017-01-17 04:00:00'),
    (25, 3, '2017-01-18 04:00:00'),
    (26, 3, '2017-01-19 04:00:00'),
    (27, 3, '2017-01-20 04:00:00'),
    (28, 1, '2018-01-05 04:00:00'),
    (29, 1, '2018-01-10 04:00:00'),
    (30, 1, '2018-01-15 04:00:00'),
    (31, 1, '2018-01-20 04:00:00'),
    (32, 1, '2018-01-22 04:00:00')
;

我在名为activities的表中也有以下数据。 一些用户记录他们几乎每天都在进行活动。 有些人每周做几次,其他人每月做几次活动如下

INSERT INTO activities
(`userId`, `activityId`, `type`, `activityDate`)
VALUES
    (1, 1, 'commit', '2018-01-01 04:00:00'),
    (1, 2, 'commit', '2018-01-02 04:00:00'),
    (1, 3, 'commit', '2018-01-03 04:00:00'),
    (1, 4, 'commit', '2018-01-04 04:00:00'),
    (1, 5, 'did', '2018-01-05 04:00:00'),
    (1, 6, 'did', '2018-01-12 04:00:00'),
    (1, 7, 'did', '2018-01-14 04:00:00'),
    (1, 8, 'did', '2018-01-29 04:00:00'),
    (1, 9, 'skipped', '2018-01-29 04:00:00'),
    (1, 10, 'did', '2018-01-29 04:00:00'),
    (1, 11, 'did', '2018-01-29 04:00:00'),
    (1, 12, 'did', '2018-01-29 04:00:00'),
    (1, 13, 'did', '2018-01-29 04:00:00'),
    (2, 14, 'commit', '2018-01-01 04:00:00'),
    (2, 15, 'did', '2018-01-02 04:00:00'),
    (2, 16, 'commit', '2018-01-03 04:00:00'),
    (2, 17, 'commit', '2018-01-04 04:00:00'),
    (2, 18, 'did', '2018-01-05 04:00:00'),
    (2, 19, 'did', '2018-01-12 04:00:00'),
    (2, 20, 'commit', '2018-01-14 04:00:00'),
    (2, 21, 'did', '2018-01-29 04:00:00'),
    (2, 22, 'skipped', '2018-01-29 04:00:00'),
    (2, 23, 'did', '2018-01-29 04:00:00'),
    (2, 24, 'did', '2018-01-29 04:00:00'),
    (2, 25, 'skipped', '2018-01-29 04:00:00'),
    (2, 26, 'did', '2018-01-29 04:00:00')

我正在尝试创建一个基于mysql的报告,它将为每个公司提供输出:

1)每周做活动类型的用户数每周一次,其中一周被定义为从公司创建之日开始。 不是日历周。 因此,如果该公司成立于03/03/17。 第一周是03/03/17 - 03/10/17,第二周是7天后直到第#x周,直到它到达当前日期。

2)acceptedInviteDate不为null的累计用户数。 只是接受的那些。 因此,例如,第3周=该公司的第1周+第2周+第3周。

这是一个示例输出:

   companyId   | week# | users_with_activity_type_did | totalUsersdWhoAcceptedAnInvite
    1          | 1     | 0                            | 0
    1          | 48    | 0                            | 0
    ....
    1          | 49    | 3                            | 28
    1          | 50    | 3                            | 29
    1          | 51    | 0                            | 30

请查看用户Sentinel开始的最新小提琴 - > http://sqlfiddle.com/#!9/4431be/1

插入的数据是正确的,但sql错误并返回错误的数据

这是使用提供的样本数据的可能解决方案。

要使这项工作,需要一个周维度表。 但请注意,根据示例数据,用户1和2在创建company_1之前就开始为Company_1工作,因此Weeks表需要有一些负数周数才能获取该数据。

有关完整设置和示例代码,请参阅此SQL Fiddle

其他MySQL 5.6架构设置

create table ones (num bigint);
insert into ones values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);

create table weeks as
select o.num + t.num * 10 + h.num * 100 week_no
  from ones o, ones t, ones h order by 1;
insert into weeks select -num from ones where num > 0;

drop table ones;

查询1

select c.id companyid
     , n.week_no
     , count(distinct case when a.type = 'did' then a.userid end) users_with_activity_type_did
     , count(distinct case when a.type = 'commit' then a.userid end) users_with_activity_type_commit
     , count(distinct case when a.type = 'skipped' then a.userid end) users_with_activity_type_skip
     , count(distinct case when u.acceptedInviteDate < (c.createdDate + interval (7*(n.week_no+1)) day)
            then u.userid
       end) totalUsersWhoAcceptedAnInvite
 from companies c
cross join weeks n
 left join users u
   on u.companyid = c.id
 left join activities a
   on a.userid = u.userid
  -- and a.type = 'did'
  and (c.createdDate + interval (7*n.week_no) day) <= a.activitydate
  and a.activitydate < (c.createdDate + interval (7*(n.week_no+1)) day)
group by c.id
    , n.week_no with rollup
having max(case when u.acceptedInviteDate < (c.createdDate + interval (7*(n.week_no+1)) day)
                 and u.acceptedInviteDate >= (c.createdDate + interval (7*(n.week_no)) day)
                then 1
                when a.activityid is not null then 1
                else 0
       end) = 1

结果

| companyid | week_no | users_with_activity_type_did | users_with_activity_type_commit | users_with_activity_type_skip | totalUsersWhoAcceptedAnInvite |
|-----------|---------|------------------------------|---------------------------------|-------------------------------|-------------------------------|
|         1 |      47 |                            0 |                               0 |                             0 |                             1 |
|         1 |      48 |                            0 |                               0 |                             0 |                             4 |
|         1 |     100 |                            2 |                               2 |                             0 |                             5 |
|         1 |     101 |                            2 |                               1 |                             0 |                             6 |
|         1 |     102 |                            0 |                               0 |                             0 |                             8 |
|         1 |     103 |                            0 |                               0 |                             0 |                             9 |
|         1 |     104 |                            2 |                               0 |                             2 |                             9 |
|         1 |  (null) |                            2 |                               2 |                             2 |                             9 |
|         2 |      52 |                            0 |                               0 |                             0 |                             1 |
|         2 |      53 |                            0 |                               0 |                             0 |                             5 |
|         2 |  (null) |                            0 |                               0 |                             0 |                             5 |
|         3 |      39 |                            0 |                               0 |                             0 |                             4 |
|         3 |      40 |                            0 |                               0 |                             0 |                             9 |
|         3 |      41 |                            0 |                               0 |                             0 |                            17 |
|         3 |      42 |                            0 |                               0 |                             0 |                            18 |
|         3 |  (null) |                            0 |                               0 |                             0 |                            18 |
|    (null) |  (null) |                            2 |                               2 |                             2 |                            32 |

我已根据您更新的示例数据更新了此答案。 另外,为每个活动类型添加单独的输出列,而不是在连接期间过滤活动类型。 如果需要,您可以删除额外的列并重新添加联接筛选器。

此外,由于活动和验收数据非常稀疏,我添加了一个having子句,仅报告用户接受或有活动的周数。

最后的更改是将with rollup子句添加到group by子句以获得一些总计。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM