如何在 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;
我有以下带有示例数据的 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;