首先让我们设置数据。我从三个表开始:players(每个玩家一行;这包括一个 id、名称和优先级 - 优先级不应出现在“分数”表中); grades 就像您的问题一样(尽管它应该看起来更像是我在下面的 with 子句中定义的 g 子查询的结果);和runs_scored,显示每场比赛和每位球员的得分。 重要提示 - 还应该有一个matches 表格(包含比赛ID 和其他详细信息,例如日期、主队、客队等);我很懒,只是从runs_scored 表中提取了匹配ID。
好的,所以数据设置如下所示:
创建或重新创建表(如果它们已经存在,请先删除它们)
drop table runs_scored purge;
drop table players purge;
drop table grades purge;
create table players (
player_id number primary key
, name varchar2(20) not null
, priority number not null unique
);
create table grades (
range varchar2(20) primary key
, grade number not null unique
);
create table runs_scored (
match_id number not null -- references matches (should have that table too)
, player_id number references players
, score number not null
, primary key (match_id, player_id)
);
填充表格
insert into players
select 1001, 'Sachin', 1 from dual union all
select 1002, 'Dhoni' , 2 from dual union all
select 1005, 'Ravi' , 3 from dual
;
insert into grades
select '0-50' , 1 from dual union all
select '50-100' , 2 from dual union all
select '100-150', 3 from dual
;
insert into runs_scored
select 1, 1001, 70 from dual union all
select 1, 1002, 45 from dual union all
select 3, 1005, 50 from dual union all
select 3, 1002, 50 from dual union all
select 3, 1001, 50 from dual union all
select 8, 1002, 160 from dual union all
select 9, 1001, 40 from dual union all
select 9, 1005, 0 from dual union all
select 9, 1002, 15 from dual
;
commit;
请注意,我假设必须为每场比赛单独分配成绩;如果不是这种情况,可以轻松修改查询,以应用所有比赛中总得分的成绩。
在输出中,我将排除未出现在runs_scored 表中的玩家,以及可能出现得分为 0 的奇数玩家(并且可能不应该包含在第一个地方)。当然,你可以有一个约束,首先要求分数 > 0。
那么这里有一种方法可以做到这一点,充分利用分析功能:
查询
with
g (runs, grade) as (
select to_number(substr(range, instr(range, '-') + 1)), grade from grades
union all
select null, 1 + max(grade) from grades
)
, matches (match_id) as ( -- there should be a MATCHES table; simulated here
select distinct match_id from runs_scored
)
, prep (match_id, player_id, name, priority, score, cumul_score, grade) as (
select rs.match_id, rs.player_id, p.name, p.priority, rs.score,
sum(rs.score) over (partition by rs.match_id order by p.priority),
cast (null as number)
from runs_scored rs join players p on rs.player_id = p.player_id
union all
select m.match_id, null, null, null, null, g.runs, g.grade
from matches m cross join g
)
, comps (match_id, cumul_score, player_id, name, score, grade) as (
select match_id, cumul_score,
last_value(player_id ignore nulls) over (partition by match_id
order by cumul_score desc, priority desc),
last_value(name ignore nulls) over (partition by match_id
order by cumul_score desc, priority desc),
cumul_score - lead(cumul_score, 1, 0) over (partition by match_id
order by cumul_score desc, priority desc),
last_value(grade ignore nulls) over (partition by match_id
order by cumul_score desc, priority desc)
from prep p
)
select match_id, player_id, name, score, grade, score * grade as final
from comps
where name is not null and score > 0
order by match_id, cumul_score;
输出
MATCH_ID PLAYER_ID NAME SCORE GRADE FINAL
---------- ---------- ---------- ----- ----- ----------
1 1001 Sachin 50 1 50
1 1001 Sachin 20 2 40
1 1002 Dhoni 30 2 60
1 1002 Dhoni 15 3 45
3 1001 Sachin 50 1 50
3 1002 Dhoni 50 2 100
3 1005 Ravi 50 3 150
8 1002 Dhoni 50 1 50
8 1002 Dhoni 50 2 100
8 1002 Dhoni 50 3 150
8 1002 Dhoni 10 4 40
9 1001 Sachin 40 1 40
9 1002 Dhoni 10 1 10
9 1002 Dhoni 5 2 10
要了解这是如何工作的,在with 子句中的每个连续子查询之后中断代码并从该子查询到select * 可能会有所帮助。您将看到每个步骤的作用。