Reputation: 258
I need to find month by month way of showing year to date unique values. For example:
created_at value
01-01-2012 a
01-01-2012 b
01-01-2012 a
01-02-2012 a
01-02-2012 a
01-02-2012 a
01-03-2012 c
01-03-2012 b
01-03-2012 b
01-04-2012 d
01-04-2012 e
01-04-2012 f
Should output:
Month Monthly unique Year to date unique
1 2 2
2 1 2
3 2 3
4 3 6
For monthly unique it is just a matter of group by and unique(), but it won't work for year-to-date this way. Year-to-date may be achieved by using for loop and filtering month by month since the beginning of the year, but it's a bad way I want to omit.
MRE:
CREATE TABLE t1 (
val varchar(5),
month int
);
(STR_TO_DATE('1-01-2012', '%d-%m-%Y'), 'a'),
(STR_TO_DATE('1-01-2012', '%d-%m-%Y'), 'b'),
(STR_TO_DATE('1-01-2012', '%d-%m-%Y'), 'a'),
(STR_TO_DATE('1-02-2012', '%d-%m-%Y'), 'a'),
(STR_TO_DATE('1-02-2012', '%d-%m-%Y'), 'a'),
(STR_TO_DATE('1-02-2012', '%d-%m-%Y'), 'a'),
(STR_TO_DATE('1-03-2012', '%d-%m-%Y'), 'c'),
(STR_TO_DATE('1-03-2012', '%d-%m-%Y'), 'b'),
(STR_TO_DATE('1-03-2012', '%d-%m-%Y'), 'b'),
(STR_TO_DATE('1-04-2012', '%d-%m-%Y'), 'd'),
(STR_TO_DATE('1-04-2012', '%d-%m-%Y'), 'e'),
(STR_TO_DATE('1-04-2012', '%d-%m-%Y'), 'f');
I created this, which gives me desired output:
select value, month
from
(
select count(distinct(val)) as value, count(distinct(month(created_at))) as month from t1 where month <=1 union
select count(distinct(val)) as value, count(distinct(month(created_at))) as month from t1 where month <=2 union
select count(distinct(val)) as value, count(distinct(month(created_at))) as month from t1 where month <=3 union
select count(distinct(val)) as value, count(distinct(month(created_at))) as month from t1 where month <=4
) t2
But it's also awful and inconvenient for filtering the main table. How to do it in efficient way?
Upvotes: 0
Views: 179
Reputation: 9050
You can do:
select
d.month as 'Month',
count(distinct d.value) as 'Monthly unique',
ytdu as 'Year to date unique'
from data d
join (
select y.month, count(distinct d2.value) as ytdu
from data y
join data d2 on d2.month<=y.month
group by y.month
) as q
where d.month=q.month
group by d.month, ytdu
See db-fiddle
Upvotes: 1
Reputation: 1758
You can get the expected result by performing subqueries for "Monthly unique" and "Year to date unique" and then combining the results.
select
s1.month as "Month",
s1.cnt as "Monthly unique",
s2.cnt as "Year to date unique"
from
-- for "Monthly unique"
( select month,count(distinct value1) as cnt
from table1 group by month) as s1
inner join
-- for "Year to date unique"
( select t2.month,count(distinct t1.value1) as cnt
from table1 as t1 cross join table1 as t2
on t1.month<=t2.month
group by t2.month) as s2
on s1.month=s2.month
Upvotes: 1