根据总分和成绩计算总贡献

问题描述

我有一个场景,需要根据总得分运行和每个年级进行计算。 以下是 2 名玩家的得分。

enter image description here

以下是需要申请的等级范围。总分是115,第一名玩家优先。所以计算从0-50,50-100和100-150。

enter image description here

因此 sachin 将有 70 次运行,其中 50 次将在 1 级以下,其余 20 次在 2 级中。 Dhoni 将从 70 开始,并在 2 年级以下的 45 到 100 中填充他的 30。 100 之后,Dhoni 剩下的 15 将被添加到 3 级。

enter image description here

寻找根据表日期 1 和 2 执行计算部分的查询。 表 3 是预期的查询输出

解决方法

首先让我们设置数据。我从三个表开始:players(每个玩家一行;这包括 ID、名称和优先级 - 优先级不应出现在“分数”表中); grades 就像在您的问题中一样(尽管它应该看起来更像是我在下面的 g 子句中定义的 with 子查询的结果);和 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,50 from dual union all
  select 8,160 from dual union all
  select 9,40 from dual union all
  select 9,0 from dual union all
  select 9,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,g.runs,g.grade
      from matches m cross join g
  ),comps (match_id,grade) as (
    select match_id,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,cumul_score - lead(cumul_score,1,0) over (partition by match_id
                                order by cumul_score desc,last_value(grade ignore nulls) over (partition by match_id
                                order by cumul_score desc,priority desc)
    from   prep p
  )
select match_id,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 * 可能会有所帮助。您将看到每个步骤的作用。