我有成员级别更改的表。它具有所有成员级别的历史变化以及发生变化时的日期。例如,我可以列出成员编号5的更改:
select * from memberlevelhistory where member = 5
结果:
member changedate level
5 2012-04-01 2
5 2012-03-01 3
5 2012-02-01 2
5 2011-02-01 6
5 2011-02-01 6
5 2010-03-15 6
5 2010-02-01 5
5 2010-01-01 5
5 2009-10-01 4
5 2009-08-27 2
5 2009-08-01 1
历史记录表中的最后一个条目是当前级别。
问题: 如何在3个月或更长时间内列出所有级别高于或等于3的成员?
这是问题的简化版本。为了让它变得更有趣,我只需要在这3个月期间内没有低于起始水平的成员。因此,如果一个成员在4个月期间开始了4级并且在上个月只是3级,那么该成员将从列表中排除。
任何帮助,即使是简化的问题也非常感谢。
扩展版本:
我还需要在过去6个月的窗口内发生> = 3个月级别> = 3的这段时间。
答案 0 :(得分:2)
这可能是not exists
的情况。如果在接下来的三个月内没有其他条目的级别低于当前选定的记录,则条目有效。这解决了这两个要求。每个成员的最后一个条目可能存在问题,其中级别适当,但跨度未知。我已决定删除这些记录,但您可能还有其他想法。
Sql Fiddle with example is here
select distinct mlh.member
from memberlevelhistory mlh
where mlh.level >= 3
and not exists
(
select null
from memberlevelhistory mlh2
where mlh2.member = mlh.member
and mlh2.changedate >= mlh.changedate
and mlh2.changedate < dateadd(month, 3, mlh.changedate)
and mlh2.level < mlh.level
)
-- The last entry might have appropriate level
-- But we cannot tell how long it lasted,
-- So we are going to remove it.
and exists
(
select null
from memberlevelhistory mlh3
where mlh3.member = mlh.member
and mlh3.changedate > mlh.changedate
)
编辑:
我已经重写了不存在()到左连接并添加了“持续到今天的最后一个条目”。
Sql Fiddle with example is here.
select distinct mlh.member
from memberlevelhistory mlh
left join memberlevelhistory mlh2
on mlh2.member = mlh.member
and mlh2.changedate >= mlh.changedate
and mlh2.changedate < dateadd(month, 3, mlh.changedate)
and mlh2.level < mlh.level
where mlh.level >= 3
and mlh2.member is null
and datediff(month, mlh.changedate, getdate()) >= 3
查询重写:
; with ranges as
(
select mlh.member, mlh.changedate StartRange, min(isnull(mlh2.changedate, getdate())) EndDate
from memberlevelhistory mlh
left join memberlevelhistory mlh2
on mlh2.member = mlh.member
and mlh2.changedate >= mlh.changedate
and mlh2.level < mlh.level
where mlh.level >= 3
group by mlh.member, mlh.changedate
having datediff (month, min(isnull(mlh2.changedate, getdate())), getdate()) <= 6
and datediff (month, mlh.changedate, min(isnull(mlh2.changedate, getdate()))) >= 3
)
select distinct member
from ranges
我认为100和101应该被包括在内,因为它们都有3个月的良好运行,并且这是在3月之前的六个月之前。
我所做的是在有人跑得好的情况下产生范围,然后测试这个范围持续3个月或更长时间以及过去六个月的结束日期。
更新:如果我最终做对了,那么持续时间在过去六个月内需要持续三个月。计算可能会将更改截断为当前日期 - 六个月。使用它作为起点,并找到范围的结束点作为第一个mlh
具有较低级别和较高日期作为结束点1具有足够的信息来计算持续时间。
; with ranges as
(
select mlh.member,
-- If good range starts more than six months before today
-- truncate it to today - 6 months
case when datediff (month, mlh.changedate, getdate()) > 6
then dateadd(month, -6, getdate())
else mlh.changedate
end StartRange,
-- First bad mlh after current changedate
min(isnull(mlh2.changedate, getdate())) EndRange
from memberlevelhistory mlh
left join memberlevelhistory mlh2
on mlh2.member = mlh.member
and mlh2.changedate >= mlh.changedate
and mlh2.level < mlh.level
where mlh.level >= 3
group by mlh.member, mlh.changedate
-- As above, limit good range to max six months before today
-- And only get those lasting at least three months
having datediff (month, case when datediff(month, mlh.changedate, getdate()) > 6
then dateadd(month, -6, getdate())
else mlh.changedate
end,
min(isnull(mlh2.changedate, getdate()))) >= 3
)
select distinct member
from ranges
答案 1 :(得分:0)
SELECT * FROM (
SELECT MEMBER, CHANGEDATE, LEVEL, COUNT(LEVEL) AS COUNT
FROM MEMBERLEVELHISTORY
GROUP BY MEMBER, CHANGEDATE, LEVEL)
WHERE LEVEL >= 3
AND COUNT >= 3;
这应该对我们的简化版本有所帮助,但为了连续分组结果超出了我的意思!