成对的 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
查询结果如下:
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
语句仅在获得最终结果之前进行评估,因此当第一个子句匹配时,不会评估剩余的子句。
您开始使用的 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