【问题标题】:case statement with pairs giving incorrect value带有不正确值的对的 case 语句
【发布时间】:2023-03-12 07:21:01
【问题描述】:

查询结果如下:

 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%然后'关键') 3) 如果至少有 1 项显着,则没有严重且(中等,有限)> 显着,则显着 4) 如果中等 >= 50% 并且没有(关键或显着),则中等 5) 休息时间有限。

我需要显着而不是有限,因为在大多数情况下,最高值胜过较低值,因此 Sig 胜过有限公司。总体而言,我希望案例陈述评估对组 (b_id,l_id),因此在对组中 1 | 10 我需要 case 语句来评估并返回结果。

【问题讨论】:

  • 这有点自相矛盾:WHEN result = 'Significant' AND result &lt;&gt; 'Critical'
  • 我不清楚您期望 Significant 而不是 Limited 的逻辑。
  • 对不起,我会把我的案例陈述清楚。
  • DISTINCT ON 没有ORDER BY 是没有意义的。
  • 对不起,我会把我的案例陈述清楚。 1)。如果至少有 1 个临界值,那么临界值。 2) 当有显着性 => 50 % 并且没有关键性时,那么关键性(这意味着如果只有 1 行并且那是显着的,所以它是 100% 然后是“关键性”),3) 如果至少有 1 个显着性,则没有关键性和(中等,有限)>显着然后显着。 4) 如果中等 >= 50% 并且没有(关键或重要),则中等,5) 休息将受到限制。

标签: sql postgresql postgresql-9.1


【解决方案1】:

使用 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

【讨论】:

  • 感谢 Remy,我找到了一个可行的解决方案,但我必须使用多个子查询才能使其工作。我测试了你的解决方案,它比我的更好。非常感谢。
【解决方案2】:

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

你永远不会得到带有1 | 10 | Critical 的行,因为表中的对应行有result = 'Significant',但avg = 33.33 所以它不能变成'Critical'。如果您希望使用“Critical”而不是“Significant”而不是“Medium”而不是“Limited”的行,那么您应该为此添加一个特定的子句,例如一个分配给每个result 级别的数值的表,这样您可以对其进行排序。

* CASE 语句只评估到获得最终结果的点,因此当第一个子句匹配时,不会评估其余子句。

【讨论】:

  • 嗨帕特里克,你是对的。我将问题从关键编辑为重要。谢谢。
【解决方案3】:

Patrick's answer 是正确的,但我会对其进行一些扩展,以使您查询中的矛盾/问题更加明确。

您开始使用的表或子查询包含这 3 行,如果您考虑它们的 所有 列,则每行都是不同的:

 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 的是,“我只想看到不同的输出行,但我希望您考虑两个输出行是不同的,基于 @ 中的值987654325@ 和 l_id 列。”

矛盾在于:

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

因为您明确告诉 PostgreSQL 将前两行视为 not distinct,所以它只选择其中 一个 行用于输出,然后选择这一行正如帕特里克解释的那样随意。

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

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 &lt;&gt; 'Critical'。)

【讨论】:

  • 嗨,丹,当我使用“DISTINCT(在所有列上)”时,我会得到所有三行,因为它们是唯一的。我在 (u_id, l_id) 上提到 distinct 的原因是,我只想要 2 行(1,10,显着)和(1, 9,关键)。谢谢
  • 感谢 Dan,您帮助解释,但您提供的代码使用 case 语句评估每一行并在行级别给出结果。我试图实现它以评估集合级别的数据并获得每个集合 1 个结果。我的“集合”是成对的组(u_id,l_id)。我该怎么做?
  • 鉴于集合中的多行可能导致不同的结果,您建议如何为 sett 选择正确的结果?在这个例子中,为什么 (1,10) 行的结果应该是 significant 而不是 limited,因为每个结果都有一行?
  • 怀疑您在这里寻找的是涉及group by 和聚合函数的东西。这是在 SQL 中以可预测的方式将多行组合成单行的“正常”方式。如果您是 SQL 新手并且不知道自己在做什么,那么您根本不应该使用DISTINCT ON
【解决方案4】:
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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-15
    • 2021-10-10
    • 2017-10-23
    相关资源
    最近更新 更多