[英]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.