Reputation: 1
I have three tables that I need to merge to analyse: active, students and bills.
'Active' contains records on active students and the subjects they have been active on with columns: id (student id) int, time (time they have been active) timestamp, and subject (subject in which were active) - text
id time subject
1 2020-04-23 06:53:30 Math
2 2020-05-13 09:51:22 Physics
2 2020-02-26 17:34:56 History
'Students' is the mass database containing: id (student id) int, group (the group to which student was assigned for a/b test) - text
id group
1 A
2 B
3 A
4 A
'Bills' keeps record of all transactions for courses that student purchased: id (student id) int, sale_time (time when student purchased course) timestamp, subject (subject in which course purchased) text, money (amount paid).
id sale_time subject money
1 2020-03-04 08:54:55 Math 4300
1 2020-04-08 20:43:56 Math 3200
2 2020-05-09 13:43:12 Law 8900
Basically, we have a student database (Students) some of which purchased courses (Bills). While some of those who purchased remain active (Active).
I need to write ONE SINGLE query where I can extract the following grouped by whether they belong to A or B group:
average revenue per user: sum (money) / count (distinct Students.id)
average revenue per active user: sum (money) / count (distinct Active.id)
conversion rate (%): count (distinct Bills.id) / count (distinct Students.id)
conversion rate (active) (%): count (distinct Bills.id) / count (distinct Active.id)
conversion rate (Math) (%) (count (distinct Bills.id) where Bills.subject = Math) / (count (distinct Active.id) where Active.subject = Math)
All these in single query!
I used
select sum (money)/count (distinct Students.id)
from Students
left join Bills using (id)
left join Active using (id)
group by group, Students.id
but I don't know how to do these math calculations all in one right after select with filters.
Please help!
SQL fiddle: https://www.db-fiddle.com/f/NPQR6aBf8H36XvrefJY2J/0
Upvotes: 0
Views: 77
Reputation: 1270431
I would recommend removing duplicates before joining and then using window functions:
select s.group, avg(b.money)as AvgPerUser,
sum(b.money) / nullif(count(a.id), 0) as AvgActUser,
count(b.id) / nullif(count(s.id), 0) as CovRate,
count(b.id) / nullif(count(a.id),0) as ConActRate,
count(b.id) filter (where s.subject = 'Math') * 1.0 / count(*) filter (where s.subject = 'Math') as ConRateMath
from Students s left join
(select b.id, sum(money) as money
from bills b
group by b.id
) b
on s.id = b.id left join
(select distinct a.id from active a
) a
on s.id = a.id
group by s.group;
Note: I don't think you want s.id
in the GROUP BY
. That really would not be aggregating anything.
Upvotes: 1
Reputation: 333
All You need is this:
select s.[group], sum (money)/ NULLIF( count (distinct s.id),0) as
AvgPerUser,
sum (money) / NULLIF(count (distinct a.id),0) as AvgActUser,
count (distinct b.id) / NULLIF(count (distinct a.id),0) as CovRate,
count (distinct b.id) / NULLIF(count (distinct a.id),0) as ConActRate,
(select count(distinct b2.id) from Bills as b2 where b2.subject = 'Math') /
NULLIF((select count ( distinct a2.id) from Active as a2 where a2.subject
='Math'),0) as ConRateMath
from Students as s
left join Bills as b on s.id = b.id
left join Active as a on s.id = a.id
group by s.[group]
Upvotes: 1