查询按类型分组,考虑具有优先级的分组

Query to group by a type considering a grouping with a priority scale

我需要根据类型并考虑优先级对一些数据进行分组。

以下面的 CTE 为例。

WITH classif AS
(
    select 1 as id, 'account' as type, 'high' as priority from dual union all
    select 2 as id, 'account' as type, 'none' as priority from dual union all
    select 3 as id, 'account' as type, 'medium' as priority from dual union all
    select 4 as id, 'security' as type, 'high' as priority from dual union all
    select 5 as id, 'security' as type, 'medium' as priority from dual union all
    select 6 as id, 'security' as type, 'low' as priority from dual union all
    select 7 as id, 'security' as type, 'none' as priority from dual union all
    select 8 as id, 'transform' as type, 'none' as priority from dual union all
    select 9 as id, 'transform' as type, 'none' as priority from dual union all
    select 10 as id, 'transform' as type, 'none' as priority from dual union all
    select 11 as id, 'transform' as type, 'none' as priority from dual union all
    select 12 as id, 'enrollment' as type, 'medium' as priority from dual union all
    select 13 as id, 'enrollment' as type, 'low' as priority from dual union all
    select 14 as id, 'enrollment' as type, 'low' as priority from dual union all
    select 15 as id, 'enrollment' as type, 'low' as priority from dual;
    select 15 as id, 'process' as type, 'low' as priority from dual;
    select 15 as id, 'process' as type, 'none' as priority from dual;
    select 15 as id, 'process' as type, 'none' as priority from dual;
)

对于这个数据集,我的输出必须是这样的

------------+-------------
type        |  priority
------------+-------------
account     |  high
security    |  high
transform   |  none
enrollment  |  medium
process     |  low
---------------------------

优先级从“高”到“none”

输出的规则必须是这样的

我正在尝试执行类似于下面这个查询的操作,但这将 return 所有行而不是根据优先级分组

select 
    type,
    case 
        when priority = 'high' then 'high'
        when priority = 'medium' and priority <> 'high' then 'medium'
        when priority = 'medium' and priority <> 'high' then 'medium'
        when priority = 'low' and priority <> 'high' or priority <> 'medium' then 'low'
        when priority = 'none' and priority <> 'high' or priority <> 'medium' or priority <> 'low' then 'none'
        end as priority        
from classif
group by type,
    case
    when priority = 'high' then 'high'
        when priority = 'medium' and priority <> 'high' then 'medium'
        when priority = 'medium' and priority <> 'high' then 'medium'
        when priority = 'low' and priority <> 'high' or priority <> 'medium' then 'low'
        when priority = 'none' and priority <> 'high' or priority <> 'medium' or priority <> 'low' then 'none'
        end;

你能帮我在查询中解决这个问题吗?

您可以使用 ROW_NUMBER 和 order by a CASE 语句将优先级转换为数值:

SELECT id, type, priority
FROM   (
  SELECT c.*,
         ROW_NUMBER() OVER (
           PARTITION BY type
           ORDER BY CASE priority
                    WHEN 'high'   THEN 1
                    WHEN 'medium' THEN 2
                    WHEN 'low'    THEN 3
                                  ELSE 4
                    END
         ) AS rn
  FROM   classif c
)
WHERE rn = 1;

或者,您可以使用 MAX(...) KEEP (DENSE RANK FIRST ...) 并使用 CASE 语句进行类似的排序:

SELECT MAX(id) KEEP (
         DENSE_RANK FIRST
         ORDER BY CASE priority
                  WHEN 'high'   THEN 1
                  WHEN 'medium' THEN 2
                  WHEN 'low'    THEN 3
                                ELSE 4
                  END
       ) AS id,
       type,
       MAX(priority) KEEP (
         DENSE_RANK FIRST
         ORDER BY CASE priority
                  WHEN 'high'   THEN 1
                  WHEN 'medium' THEN 2
                  WHEN 'low'    THEN 3
                                ELSE 4
                  END
       ) AS priority
FROM   classif
GROUP BY type

或者,您可以使用子查询来存储相对优先级并使用连接:

SELECT MAX(c.id) KEEP (DENSE_RANK LAST ORDER BY p.id) AS id,
       type,
       MAX(c.priority) KEEP (DENSE_RANK LAST ORDER BY p.id) AS priority
FROM   classif c
       LEFT OUTER JOIN (
         SELECT 'high' AS priority, 3 As id FROM DUAL UNION ALL
         SELECT 'medium', 2 FROM DUAL UNION ALL
         SELECT 'low',    1 FROM DUAL UNION ALL
         SELECT 'none',   0 FROM DUAL
       ) p
       ON c.priority = p.priority
GROUP BY c.type

其中,对于您的示例数据,所有输出:

ID TYPE PRIORITY
1 account high
12 enrollment medium
15 process low
4 security high
8 transform none

db<>fiddle here