Oracle / SQL - 使用rank函数

时间:2011-09-12 21:57:09

标签: sql oracle rank

我要做的是从一张桌子上的人员列表,如果一个人不止一次存在,那么返回他们包含排名最高的“代码”的记录

代码排名(从高到低):T,E,F

因此对于给定的数据集

Person  Code
----------------    
Tom     F
Paul    E
Mark    F
Paul    T
Mark    E
Chris   T
Chris   E

我会从查询中得到以下内容

Person  Code
----------------
Tom     F
Paul    T
Mark    E
Chris   T

我假设这将使用排名/分析函数,但我对它们不够熟悉。

谢谢!

4 个答案:

答案 0 :(得分:2)

您可以使用RANK功能对数据进行排名

SQL> ed
Wrote file afiedt.buf

  1  with data as (
  2    select 'Tom' person, 'F' code from dual union all
  3    select 'Paul', 'E' from dual union all
  4    select 'Paul', 'T' from dual union all
  5    select 'Mark', 'F' from dual union all
  6    select 'Mark', 'E' from dual
  7  )
  8  select *
  9    from (select person,
 10                 code,
 11                 rank() over (partition by person
 12                                  order by (case when code='T' then 1
 13                                                 when code='E' then 2
 14                                                 when code='F' then 3
 15                                                 else null
 16                                             end)) rnk
 17*           from data)
SQL> /

PERS C        RNK
---- - ----------
Mark E          1
Mark F          2
Paul T          1
Paul E          2
Tom  F          1

Elapsed: 00:00:00.00

然后,您只需选择RNK为1

的行
SQL> ed
Wrote file afiedt.buf

  1  with data as (
  2    select 'Tom' person, 'F' code from dual union all
  3    select 'Paul', 'E' from dual union all
  4    select 'Paul', 'T' from dual union all
  5    select 'Mark', 'F' from dual union all
  6    select 'Mark', 'E' from dual
  7  )
  8  select *
  9    from (select person,
 10                 code,
 11                 rank() over (partition by person
 12                                  order by (case when code='T' then 1
 13                                                 when code='E' then 2
 14                                                 when code='F' then 3
 15                                                 else null
 16                                             end)) rnk
 17            from data)
 18*  where rnk = 1
SQL> /

PERS C        RNK
---- - ----------
Mark E          1
Paul T          1
Tom  F          1

Elapsed: 00:00:00.00

答案 1 :(得分:0)

我认为RANK不是你需要的......

基本上,你的删除将如下所示:(伪查询)

delete the rows from person
where that row is not in ( select the rows from person with the highest code )

修改

这个技巧也可能对你有所帮助:

select person, code, decode( code, 'T', 1, 'E', 2, 'F', 3, 0 ) from mytable

答案 2 :(得分:0)

Hum ...标准SQL的替代建议。 有一个CODE_WEIGHT表,例如:

CODE WEIGHT
T    3    
E    2
F    1

然后按Person分组查询(如果这是分组标准)并选择包含max(weight)的不同代码。

我会在几分钟内发布查询。

<强>更新

好的,抱歉延误了。

这是使用前面提到的表和@Randy技巧的解决方案:

SELECT 
 pp.person, decode(max(c.weight), 3, 'T', 2, 'E', 1, 'F', '') code
FROM 
 person pp INNER JOIN code_weight c on (pp.code = c.code)
GROUP BY
 pp.person 
ORDER BY 
 person DESC;

我很确定有一种方法可以转储Oracle专有功能并在纯SQL中完成工作......无论如何,既然你已经要求提供Oracle解决方案,那么就是这样。

更新2

正如所承诺的,这是我能够提出的最好的标准SQL版本:

SELECT 
 p.person, c.code
FROM
(
 SELECT 
   pp.person, MAX(cc.weight) weight
 FROM 
  person pp INNER JOIN code_weight cc ON (pp.code = cc.code)
 GROUP BY
  pp.person 
) p INNER JOIN code_WEIGHT c ON (p.weight = c.weight)
ORDER BY
  p.person DESC;

有点丑陋的两个连接...但它没有专有扩展的工作。任何SQL大师都知道如何优化它?

干杯,

答案 3 :(得分:0)

最短,性能最高且特定于Oracle的解决方案:

SQL> create table mytable(person,code)
  2  as
  3  select 'Tom', 'F' from dual union all
  4  select 'Paul', 'E' from dual union all
  5  select 'Mark', 'F' from dual union all
  6  select 'Paul', 'T' from dual union all
  7  select 'Mark', 'E' from dual union all
  8  select 'Chris', 'T' from dual union all
  9  select 'Chris', 'E' from dual
 10  /

Table created.

SQL> select person
  2       , max(code) keep (dense_rank first order by decode(code,'T',1,'E',2,'F',3,4)) code
  3    from mytable
  4   group by person
  5  /

PERSO C
----- -
Chris T
Mark  E
Paul  T
Tom   F

4 rows selected.

的问候,
罗布。