5

我有成员级别更改的表格。它具有所有成员级别的历史变化和发生变化的日期。例如,我可以列出成员编号 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 个月期间没有低于起始水平的成员。因此,如果成员在 3 个月期间以 4 级开始,并且在上个月仅为 3 级,则该成员将被排除在列表之外。

任何帮助,即使是简化的问题,也非常感谢。

扩大的视野:

我还需要在过去 6 个月的窗口内发生 >=3 个月的水平 >=3 的时期。

4

2 回答 2

2

这可能是not exists. 如果在接下来的三个月内没有其他条目的级别低于当前选择的记录,则该条目有效。这解决了这两个要求。在级别合适但跨度未知的情况下,每个成员的最后一个条目可能存在问题。我已决定删除这些记录,但您可能有其他想法。

带有示例的 Sql Fiddle 在这里

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
       )

编辑:

我已将 not exists() 重写为左连接并添加了“最后一个条目持续到今天”标准。

带有示例的 Sql Fiddle 在这里。

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

而 Sql Fiddle 就在这里

我认为应该包括 100 和 101,因为两者都在 3 个月内运行良好,而这发生在 3 月,也就是在这一刻之前的 6 个月。

我所做的是在某人运行良好时生成范围,然后在 3 个月或更长时间的持续时间和过去六个月的结束日期测试此范围。

更新:如果我最终做对了,您需要在过去六个月中持续三个月。计算一个可能会将更改日期截断为当前日期 - 六个月。使用它作为起点,并找到一个范围的终点,首先mlh以较低级别和较高日期作为终点,有足够的信息来计算持续时间。

; 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

带有示例的 Sql Fiddle 在这里

于 2012-09-03T10:07:15.357 回答
0
SELECT * FROM (
  SELECT MEMBER, CHANGEDATE, LEVEL, COUNT(LEVEL) AS COUNT
  FROM MEMBERLEVELHISTORY
  GROUP BY MEMBER, CHANGEDATE, LEVEL)
WHERE LEVEL >= 3
AND COUNT >= 3;

这应该对您的简化版本有所帮助,但是为了连续分组结果超出了我的范围!

于 2012-09-03T02:22:40.513 回答