【问题标题】:查询以考虑具有优先级的分组的类型进行分组
【发布时间】:2021-12-08 15:58:48
【问题描述】:

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

以下面的 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
---------------------------

优先级从“高”到“无”

输出的规则一定是这样的

  • 当一个类型有一个优先级为“high”的行时,该类型的输出必须是“high”。
  • 当一个类型有一个优先级为“中”的行并且没有其他的 使用“高”,输出必须为“中”。
  • 当一个类型有一个优先级“低”的行并且没有其他的 使用“高”或“中”,输出必须为“低”。
  • 当一个类型有一个优先级为“none”的行并且没有任何 其他,输出必须为“无”

我正在尝试执行类似下面的查询,但这将返回所有行而不是根据优先级进行分组

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;

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

【问题讨论】:

  • 您最好创建一个映射表,而不是尝试处理查询中的条件值。

标签: sql oracle greatest-n-per-group


【解决方案1】:

您可以使用ROW_NUMBER 并按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小提琴here

【讨论】:

  • 哇!非常感谢。第一个和第二个解决方案对我来说效果很好!
猜你喜欢
  • 2023-03-15
  • 2021-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多