如何按自定义周定义记录分组?

时间:2018-12-28 15:31:47

标签: mysql sql

我正在尝试将一个将在MySQL中运行的SQL报表汇总在一起。

我有一个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)每周执行活动类型 did 的每周用户数,其中一周定义为从公司创建之日起。不是日历周。因此,如果公司成立于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 个答案:

答案 0 :(得分:1)

以下是使用提供的示例数据的可能解决方案。

要进行此工作,需要一个Weeks维度表。但是请注意,基于样本数据的用户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

Results

| 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子句以获得总计。