POSTGRES:如何仅在另一个值不存在时选择具有某个值的行,在这种情况下选择另一个值?
Posted
技术标签:
【中文标题】POSTGRES:如何仅在另一个值不存在时选择具有某个值的行,在这种情况下选择另一个值?【英文标题】:POSTGRES: How to select rows with a certain value only if another value doesn't exist, and in that case select the other value? 【发布时间】:2022-01-24 03:48:33 【问题描述】:这是我正在使用的表的示例。我想要实现的是选择类型不是“NONE”的最新行,除非“NONE”是该id唯一可用的类型。
id | date | type |
---|---|---|
123 | 01-01-2021 | NONE |
123 | 12-31-2021 | NONE |
123 | 01-01-2021 | METAL |
123 | 12-31-2021 | METAL |
从上面的示例表中,我希望查询返回这个
id | date | type |
---|---|---|
123 | 12-31-2021 | METAL |
如果表格只包含“NONE”类型,例如这个例子......
id | date | type |
---|---|---|
123 | 01-01-2021 | NONE |
123 | 12-31-2021 | NONE |
123 | 01-01-2021 | NONE |
123 | 12-31-2021 | NONE |
那么我希望结果集是..
id | date | type |
---|---|---|
123 | 12-31-2021 | NONE |
我已经尝试了很多不同的方法来做到这一点,但我目前的尝试看起来像这样。它在表中只有一个 ID 时有效,但不适用于我尝试为表中的每个特定 ID 选择一行时。
SELECT DISTINCT ON (id),
date,
type
FROM
example_table
WHERE
CASE
WHEN
( SELECT
COUNT(*)
FROM
example_table t
WHERE
t.type <> 'NONE'
AND t.id = example_table.id)
<> 0
THEN type <> 'NONE'
ELSE 1=1
END
ORDER BY
id, date DESC
【问题讨论】:
【参考方案1】:您可以将 Row_number() 函数与 case 语句一起使用来确定要选择的行。
with cte AS
(
select id,
date,
type,
row_number() over(partition by id
order by case when type <> 'NONE' THEN 1 ELSE 2 END, date desc
) as RN
from test
)
select *
from cte
where rn = 1
SQL Fiddle
【讨论】:
谢谢我喜欢这个。如果您能帮助我理解 case 语句的工作原理,特别是 order by 子句中的 THEN 1 ELSE 2 部分,我将不胜感激。按 1 订购 2 订购?这是在做什么? 使用case语句,你基本上是为类型分配权重,然后使用权重对它们进行排序。 您正在为“无”以外的值分配较小的数字,以便在您订购它们时它们会排在第一位。 啊,谢谢。我从不知道您可以使用 order by 并分配这样的权重。【参考方案2】:不使用分析函数: SQL:
with cte
as
(
select id,type,flag, max(date) date from (select id , date , type, case when type='NONE' then 'flag_none' else 'flag_not_none' end as flag from test) x group by id,type,flag)
select id,type,date from cte where flag='flag_not_none' and (id,date) in (select id,max(date) from cte group by id)
union
select id,type,date from cte where id not in (select id from cte where flag='flag_not_none' and (id,date) in (select id,max(date) from cte group by id)) and flag='flag_none';
完全执行:
CREATE TABLE test
(
id int,
date date,
type text
);
insert into test
values
(123, '01-01-2021', 'NONE'),
(123, '12-31-2021', 'NONE'),
(123, '01-01-2021', 'METAL'),
(123, '12-31-2021', 'PLASTIC'),
(124, '01-01-2021', 'NONE'),
(124, '12-31-2021', 'NONE'),
(124, '01-01-2021', 'NONE'),
(124, '12-31-2021', 'NONE'),
(125, '12-25-2021', 'NONE'),
(125, '12-25-2021', 'RUBBER'),
(125, '12-31-2021', 'STEEL');
postgres=# with cte
postgres-# as
postgres-# (
postgres(# select id,type,flag, max(date) date from (select id , date , type, case when type='NONE' then 'flag_none' else 'flag_not_none' end as flag from test) x group by id,type,flag)
postgres-# select id,type,date from cte where flag='flag_not_none' and (id,date) in (select id,max(date) from cte group by id)
postgres-# union
postgres-# select id,type,date from cte where id not in (select id from cte where flag='flag_not_none' and (id,date) in (select id,max(date) from cte group by id)) and flag='flag_none';
id | type | date
-----+---------+------------
123 | PLASTIC | 2021-12-31
124 | NONE | 2021-12-31
125 | STEEL | 2021-12-31
(3 rows)
【讨论】:
以上是关于POSTGRES:如何仅在另一个值不存在时选择具有某个值的行,在这种情况下选择另一个值?的主要内容,如果未能解决你的问题,请参考以下文章