我正在尝试将一个将在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错误并返回错误数据
答案 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
子句以获得总计。