如何在 oracle sql 中找到 <N> 连续的销售奖金

how to find <N> consecutive sales bonus in oracle sql

我有以下带有示例数据的 Table 定义。

Table: target_bonus

branch   month    bonus
  1        1       100
  1        2       0
  1        3       200
  1        4       150
  1        5       175
  1        6       180
  1        7       125
  1        8       0
  1        9       0
  1        10      0
  1        11      125
  1        12      130
  2        1       0
  2        2       0
  2        3       200
  2        4       150
  2        5       175
  2        6       180
  2        7       125
  2        8       110
  2        9       105
  2        10      115
  2        11      125
  2        12      130

鉴于上述table,我需要按月找到奖金不为零的N条或更多条连续记录。例如,如果 N = 3,结果集将 return 如下:

branch     month     bonus
  1        3       200
  1        4       150
  1        5       175
  1        6       180
  1        7       125
  2        3       200
  2        4       150
  2        5       175
  2        6       180
  2        7       125
  2        8       110
  2        9       105
  2        10      115
  2        11      125
  2        12      130

这建立在这个答案的基础上:

基于那个技巧,我们需要先生成一组可以使用的连续值。那么可以采取同样的做法:

with flagged as (
  select t.*,
         case
            when (bonus > 0) then row_number() over (partition by branch order by month) 
            else 0
          end as bonus_rn
  from target_bonus t
), numbered as (
  select f.*,
         bonus_rn - row_number() over (partition by branch order by month)  as grp
  from flagged f
), grouped as (
  select n.*,
         sum(grp) over (partition by branch order by month) as grp_nr
  from numbered n
), cons as (
  select g.*,
         count(*) over (partition by branch, grp_nr) as num_consecutive
  from grouped g
  where bonus > 0
)
select branch, month, bonus
from cons
where num_consecutive > 1 -- change here if you want 
order by branch, month;

以上可能可以简化,但我发现如果我可以检查这种方法的每个步骤的结果,调试起来会更容易。

另一种查询(更类似于链接答案中的查询)将只显示每个 "interval":

的开始和结束月份
with flagged as (
  select t.*,
         case
            when (bonus > 0) then row_number() over (partition by branch order by month) 
            else 0
          end as bonus_rn
  from target_bonus t
), numbered as (
  select f.*,
         bonus_rn - row_number() over (partition by branch order by month)  as grp
  from flagged f
), grouped as (
  select n.*,
         sum(grp) over (partition by branch order by month) as grp_nr
  from numbered n
)
select branch, 
       min(month) as start_month, 
       max(month) as end_month ,
       count(*) as num_consecutive
from grouped 
group by branch, grp_nr
having count(*) > 1 -- change here if you want 
order by branch, start_month;

这个解决方案对于大表来说并不是很快。

SQLFiddle:http://sqlfiddle.com/#!4/90b4c/1

也许这会有所帮助:

SELECT x.*
  FROM(SELECT branch, e, f
         FROM(SELECT branch,
                     LEAD(month, 1, 13) OVER (PARTITION BY branch ORDER BY month) - month - 1 AS d,
                     month + 1 AS e,
                     LEAD(month, 1, 13) OVER (PARTITION BY branch ORDER BY month) - 1 AS f
                FROM(SELECT DISTINCT
                            branch, 0 AS month, 0 AS bonus
                       FROM target_bonus x
                      UNION
                     SELECT branch, month, bonus
                       FROM target_bonus x
                    )
               WHERE bonus = 0
             )        
        WHERE d >= 3 -- This is your N
      ) y
  JOIN target_bonus x
    ON x.branch = y.branch
   AND x.month BETWEEN y.e AND y.f
 ORDER
    BY x.branch, x.month;