成对的 case 语句给出了不正确的值

case statement with pairs giving incorrect value

查询结果如下:

 b_id| l_id | result    | Count | avg
-----+------+--------- -+-------+-----
   1 |   10 | Limited   |   2   | 66.66
   1 |   10 |Significant|   1   | 33.33
   2 |   09 | Critical  |   1   |100.00  

我正在努力使用如下的 case 语句来获得正确的查询:

SELECT DISTINCT ON (b_id, l_id) b_id, l_id, 
            (CASE
                WHEN result = 'Critical' THEN 'Critical'
                WHEN result = 'Significant' AND avg >= 50 THEN 'Critical'
                WHEN result = 'Significant' AND result <> 'Critical' THEN 'Significant'
                WHEN result = 'Medium' AND avg >= 50 THEN 'Medium'
                ELSE 'Limited' END) as cr                   
From (sub query)

我得到的结果如下:

 b_id| l_id | result    
-----+------+----------
   1 |   10 | Limited   
   2 |   09 | Critical

但我的期望如下:

 b_id| l_id | result    
-----+------+----------
   1 |   10 | significant   
   2 |   09 | Critical

1).如果至少有 1 个关键,则关键。 2) 当有显着性 => 50 % 并且没有关键性时则为关键性(这意味着如果只有 1 行并且那是重要的所以它是 100% 那么 'critical') 3) 如果至少有 1 个显着,则没有关键且 (medium, limited) > significant then significant 4) 如果 medium >= 50% 并且没有(关键或显着)那么 medium 5) 休息时间有限

我需要 Significant 而不是 limited,因为在大多数情况下最高值胜过较低的值,所以 Sig 胜过 Ltd。总的来说,我希望案例陈述评估成对组 (b_id,l_id) 所以在对组中 1 | 10 我需要案例陈述来评估和 return 结果。

撇开 WHEN result = 'Significant' AND result <> 'Critical' THEN 'Significant' 问题*,所有三行都符合条件,然后由于 DISTINCT ON (b_id, l_id),前两行中的其中一行被选中。您无法控制将选择两行中的哪一行,这基本上取决于您的数据在磁盘上的组织方式,并且可能会随时间变化。

你永远不会得到 1 | 10 | Critical 的行,因为 table 的对应行有 result = 'Significant'avg = 33.33 所以它不能变成 'Critical'.如果你想支持 "Critical" 超过 "Significant" 超过 "Medium" 超过 "Limited" 的行,那么你应该为此添加一个特定的子句,例如 table 与分配给每个 result 级别的数值,以便您可以对其进行排序。

* CASE 语句仅在获得最终结果之前进行评估,因此当第一个子句匹配时,不会评估剩余的子句。

是正确的,但我会稍微扩展一下,使您查询中的 contradiction/problem 更明确。

您开始使用的 table 或子查询包含这些 3 行,如果您考虑 all[=49,则每行都是不同的=] 他们的专栏:

 b_id| l_id | result    | Count | avg
-----+------+--------- -+-------+-----
   1 |   10 | Limited   |   2   | 66.66
   1 |   10 |Significant|   1   | 33.33
   2 |   09 | Critical  |   1   |100.00  

但是,您 运行 的查询使用 DISTINCT ON 只有 2 列:

SELECT DISTINCT ON (b_id, l_id) b_id, l_id, …

你在这里明确告诉 PostgreSQL 的是,"I only want to see distinct output rows, but I want you to consider two output rows to be distinct based only on the values in the b_id and l_id columns."

矛盾就在这里:

  • 如果您考虑所有它们的列
  • ,所有 3 行都是不同的
  • ... 但是 (b_id, l_id) 只有两个不同的元组:(1,10)(2,09)

因为您明确告诉 PostgreSQL 将前两行视为不明显,所以它只选择其中的一个行用于输出,它会按照 Patrick 的解释任意选择这一行。

我不确定你为什么首先使用 DISTINCT ON (x, y, z)。如果您只是将其替换为 DISTINCT(在所有列上),则查询将 return 您期望的结果:

SELECT DISTINCT b_id, l_id, 
            (CASE
                WHEN result = 'Critical' THEN 'Critical'
                WHEN result = 'Significant' AND avg >= 50 THEN 'Critical'
                WHEN result = 'Significant' THEN 'Significant'
                WHEN result = 'Medium' AND avg >= 50 THEN 'Medium'
                ELSE 'Limited' END) as cr                   
From (sub query)

(我还删除了其他人注意到的冗余 result <> 'Critical'。)

使用bool_or聚合(至少一行的条件为真):

SELECT b_id, l_id,CASE WHEN bool_or(result='Critical' or (result = 'Significant' AND avg >= 50) ) Then 'Critical' 
           WHEN bool_or(result='Significant') THEN 'Significant'
           WHEN bool_or(result = 'Medium' AND avg >= 50) THEN 'Medium'
           ELSE 'Limited' END as cr 
 From (sub query) group by 1,2
select b_id, l_id, (CASE WHEN result = 'Critical' THEN 'Critical'
            WHEN (result = 'Significant' AND avg >= 50) THEN 'Critical'
            WHEN result = 'Significant' THEN 'Significant'
            WHEN result = 'Medium' AND avg >= 50 THEN 'Medium'
            WHEN result = 'Limited' THEN 'Limited' END) as result
from (
    select business_unit_id, law_id, result, avg
from (
    SELECT b_id, l_id, avg, result, ROW_NUMBER() over(PARTITION BY b_id, l_id order by CASE
            WHEN result = 'Critical' THEN 1
            WHEN result = 'Significant' AND avg >= 50 THEN 1
            WHEN result = 'Significant' THEN 2
            WHEN result = 'Medium' AND avg >= 50 THEN 3
            WHEN result = 'Limited' THEN 4 END) as rownum

from (
    sub_query     ) b            ) x where rownum = 1              ) y