【问题标题】:Select with condition and check有条件选择并检查
【发布时间】:2022-01-21 23:14:47
【问题描述】:

这是我的桌子:

project_id | task_id | task_name | task_status |
  ---------+---------+-----------+-------------+
      1           12     foo       complete
      2           13     foo       complete
      3         1210     bar       complete
      4         1211     bar         none
      5         1212     xyz         none
      6         1213     zyz         none

我想创建查询,我只能选择tasks_name,其中task_status“完成”两个task_id。例如,一个名为foo 的任务有两个task_id,例如12 和13,它们都有task_status 完成。相比之下,名称为bar 的任务只有一个task_id“已完成”,所以它不符合我的条件。 我希望得到这样的表格:

   project_id | task_id | task_name | task_status |
     ---------+---------+-----------+-------------+
         1           12     foo       complete
         2           13     foo       complete

我如何选择、检查和返回 task_name 与每个 task_id 相同的位置,并且它们都完成了 task_status

【问题讨论】:

  • 对于两个不同的任务,project_id 是否总是唯一的或至少不同?如果有两个以上同名且complete 状态的任务怎么办?

标签: sql postgresql


【解决方案1】:

使用 min、max 和子查询更容易做到这一点。

Select *
From Tbl
Where task_name In (Select task_name
                    From Tbl
                    Group by task_name
                    Having Min(task_status)=Max(task_status)                
                           And Max(task_status)='complete')

数据输出:

project_id | task_id | task_name | task_status                         
___________|_________|___________|____________
         1 |      12 | foo       | complete    
         2 |      13 | foo       | complete   

【讨论】:

    【解决方案2】:

    这意味着,每个任务名称,完成的数量需要与总数相同。

    select project_id, task_id, task_name, task_status
    from 
    (
      select *
      , count(case when task_status = 'complete' then 1 end) 
         over (partition by task_name) as cnt_complete
      , count(*) 
         over (partition by task_name) as cnt
      from yourtable
    ) q
    where cnt = cnt_complete
    
    project_id task_id task_name task_status
    1 12 foo complete
    2 13 foo complete

    dbfiddle here

    上的演示

    【讨论】:

      【解决方案3】:

      使用窗口函数过滤所有完整的任务名称。

      select project_id, task_id, task_name, task_status from 
      (
       select *,
        count(*) filter (where task_status = 'complete') over w = count(*) over w all_complete
        from the_table window w as (partition by task_name)
      ) t 
      where all_complete; 
      

      【讨论】:

        【解决方案4】:

        一种方法,使用解析函数:

        WITH cte AS (
            SELECT *, MIN(task_status) OVER (PARTITION BY task_name) min_task_status,
                      MAX(task_status) OVER (PARTITION BY task_name) max_task_status
            FROM yourTable
        )
        
        SELECT project_id, task_id, task_name, task_status
        FROM cte
        WHERE min_task_status = max_task_status AND
              min_task_status = 'complete';
        

        【讨论】:

        • Oracle 一路走来 :)
        • @Stefanov.sm 除了我的答案甚至不会在 Oracle 上运行。检查CTE,表名没有别名,所以SELECT *会报错。
        • 我的笑话是关于调用窗口函数“分析”。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-31
        • 1970-01-01
        • 2011-08-10
        • 1970-01-01
        相关资源
        最近更新 更多