【问题标题】:POSTGRES: How to select rows with a certain value only if another value doesn't exist, and in that case select the other value?POSTGRES:如何仅在另一个值不存在时选择具有某个值的行,在这种情况下选择另一个值?
【发布时间】: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

 

【问题讨论】:

    标签: sql database postgresql


    【解决方案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)
    

    【讨论】:

      猜你喜欢
      • 2014-02-21
      • 2015-12-03
      • 2011-02-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-01
      相关资源
      最近更新 更多