我认为,您的特定应用程序使这变得非常简单。如果在“n”天的间隔中有“n”个不同的日期,那么这些“n”个不同的日期必须是连续的。
滚动到底部以获取仅需要公用表表达式并更改为 PostgreSQL 的通用解决方案。(开玩笑。我是在 PostgreSQL 中实现的,因为我时间不够。)
create table ForumPost (
ID integer primary key,
UserID integer not null,
post_date date not null
);
insert into forumpost values
(1, 1, '2013-01-15'),
(2, 1, '2013-01-16'),
(3, 1, '2013-01-17'),
(4, 1, '2013-01-18'),
(5, 1, '2013-01-19'),
(6, 1, '2013-01-20'),
(7, 1, '2013-01-21'),
(11, 2, '2013-01-15'),
(12, 2, '2013-01-16'),
(13, 2, '2013-01-17'),
(16, 2, '2013-01-17'),
(14, 2, '2013-01-18'),
(15, 2, '2013-01-19'),
(21, 3, '2013-01-17'),
(22, 3, '2013-01-17'),
(23, 3, '2013-01-17'),
(24, 3, '2013-01-17'),
(25, 3, '2013-01-17'),
(26, 3, '2013-01-17'),
(27, 3, '2013-01-17');
现在,让我们看看这个查询的输出。为简洁起见,我正在查看 5 天的间隔,而不是 30 天的间隔。
select userid, count(distinct post_date) distinct_dates
from forumpost
where post_date between '2013-01-15' and '2013-01-19'
group by userid;
USERID DISTINCT_DATES
1 5
2 5
3 1
对于符合条件的用户,该 5 天间隔内的不同日期数必须为 5,对吗?所以我们只需要将该逻辑添加到 HAVING 子句中。
select userid, count(distinct post_date) distinct_dates
from forumpost
where post_date between '2013-01-15' and '2013-01-19'
group by userid
having count(distinct post_date) = 5;
USERID DISTINCT_DATES
1 5
2 5
更通用的解决方案
说真的没有道理,如果你从 2013 年 1 月 1 日到 2013 年 1 月 31 日每天发帖,你已经连续 30 天发了 2 次。相反,我希望时钟在 2013 年 1 月 31 日重新开始。我很抱歉在 PostgreSQL 中实现;稍后我将尝试在 T-SQL 中实现。
with first_posts as (
select userid, min(post_date) first_post_date
from forumpost
group by userid
),
period_intervals as (
select userid, first_post_date period_start,
(first_post_date + interval '4' day)::date period_end
from first_posts
), user_specific_intervals as (
select
userid,
(period_start + (n || ' days')::interval)::date as period_start,
(period_end + (n || ' days')::interval)::date as period_end
from period_intervals, generate_series(0, 30, 5) n
)
select userid, period_start, period_end,
(select count(distinct post_date)
from forumpost
where forumpost.post_date between period_start and period_end
and userid = forumpost.userid) distinct_dates
from user_specific_intervals
order by userid, period_start;