Oracle SQL 按列值排名分组

Oracle SQL Group By Column Value Rank

我最近开始学习Oracle中的数据库查询,但是有一件事我对分组理解起来很费劲。

最好用例子来解释。假设我有如下所示的源数据:

MY_SOURCE

ID | Fruit
----------
1  | Orange
1  | Apple
1  | Orange
2  | Banana
2  | Apple
3  | Apple
3  | Apple
3  | Orange

假设水果的某些值有不同rank/priority。假设排名(1=最重要;3=最不重要)是:

Fruit Rank:
1. Banana
2. Orange
3. Apple

我想按 ID 对数据进行分组。当我这样做时,数据源中每个 ID 的水果列都会有重复项,必须进行聚合。例如,对于 ID one,一组可能的值是:

Orange, Apple, Orange

此时,我不想用 stats_mode() 之类的方法聚合重复的水果集,而是想按水果等级对数据进行分组,并只显示排名最高的值。因此,输出将是:

ID | Fruit
----------
1  | Orange
2  | Banana
3  | Orange

在 SQL 中有没有办法做到这一点?

我正在想象一个看起来像这样的查询:

SELECT DISTINCT
    ID,
    MAGIC_MAX_RANK_FUNCTION(FRUIT, ['Banana','Orange', 'Apple'])
FROM
    MY_SOURCE

在技术术语中,我们根据程序员为该列的所有可能值指定的等级对重复的水果数据进行分组。

提前致谢!

而不是 GROUP BY,我会使用 ROW_NUMBER():

select s.*
from (select s.*,
             row_number() over (partition by id
                                order by (case fruit when 'banana' then 1 when 'orange' then 2 when 'apple' then 3 else 999 end)
                               ) as seqnum
      from my_source s
     ) s
where seqnum = 1;

另一种方法使用 union all 并且最适合短列表:

select s.*
from my_source s
where s.fruit = 'banana'
union all
select s.*
from my_source s
where s.fruit = 'orange' and
      not exists (select 1 from my_source s2 where s2.id = s.id and s2.fruit in ('banana'))
union all
select s.*
from my_source s
where s.fruit = 'apple' and
      not exists (select 1 from my_source s2 where s2.id = s.id and s2.fruit in ('banana', 'orange'));

在某些情况下,此方法可能比以前的方法更快(反之亦然)。