必要なすべての日付を含むカレンダーテーブルがある場合、このような問題は簡単に解決できます。このようなテーブルがない場合は、次のようなクエリで作成できます。
create table `calendar` (
`date` DATE NOT NULL,
PRIMARY KEY (`date`)
)
select DATE_ADD('1900-01-01',INTERVAL t4.c*10000 + t3.c*1000 + t2.c*100 + t1.c*10 + t0.c DAY) as `date`
from
(select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t0,
(select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1,
(select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3,
(select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4
これにより、1900-01-01から2173-10-15(100K日)までの日付のテーブルが作成され、約2.5MBしか消費されません。必要に応じて調整できます。
カレンダーテーブルを使用すると、3か月の範囲を取得できます:
select
DATE_FORMAT(date_sub(c.date, INTERVAL 1 day), '%Y-%m') as month,
date_sub(c.date, INTERVAL 3 month) as first_day,
date_sub(c.date, INTERVAL 1 day) as last_day
from calendar c
where day(c.date) = 1
and c.date between '2015-02-01' and '2015-09-01'
結果:
| month | first_day | last_day |
| 2015-01 | 2014-11-01 | 2015-01-31 |
| 2015-02 | 2014-12-01 | 2015-02-28 |
| 2015-03 | 2015-01-01 | 2015-03-31 |
| 2015-04 | 2015-02-01 | 2015-04-30 |
| 2015-05 | 2015-03-01 | 2015-05-31 |
| 2015-06 | 2015-04-01 | 2015-06-30 |
| 2015-07 | 2015-05-01 | 2015-07-31 |
| 2015-08 | 2015-06-01 | 2015-08-31 |
本当に90日間隔のようなものを使用したい場合は、調整してください。
これで、ログインテーブルとの単純な左結合で、必要なものを取得できます。
select i.month as `Date`, count(distinct l.user_id) as `Active users`
from (
select
date_format(date_sub(c.date, interval 1 day), '%Y-%m') as month,
date_sub(c.date, interval 3 month) as first_day,
date_sub(c.date, interval 1 day) as last_day
from calendar c
where day(c.date) = 1
and c.date between '2015-02-01' and '2015-09-01'
) i
left join login_table l on l.login_date between i.first_day and i.last_day
group by i.month
http://sqlfiddle.com/#!9/d1bb0/3