【问题标题】:SQL group by with Case statementSQL group by with Case 语句
【发布时间】:2020-10-26 14:33:58
【问题描述】:

我有一张看起来像这样的表

+-----------+-----------+---------------------+
| Report_id |  Status   |        Date         |
+-----------+-----------+---------------------+
|         1 | Completed | 2020-06-07 12:20:00 |
|         1 | Completed | 2020-06-07 12:22:00 |
|         2 | Running   | 2020-06-07 13:02:00 |
|         2 | Completed | 2020-06-07 13:10:00 |
|         3 | Completed | 2020-06-07 14:10:00 |
|         3 | Failed    | 2020-06-07 14:04:00 |
+-----------+-----------+---------------------+

我需要按 Report_id 对这些数据进行分组。因此,如果组内的所有状态值都等于 Completed,则 Status 是 Completed 并且 Date 是组内的最大值。但是,如果组内有一个 Running 或 Failed 值,则 Status 需要分别等于 Running 和 Failed 并且 Date 应该匹配此值。

输出将如下所示。

+-----------+-----------+---------------------+
| Report_id |  Status   |        Date         |
+-----------+-----------+---------------------+
|         1 | Completed | 2020-06-07 12:22:00 |
|         2 | Running   | 2020-06-07 13:02:00 |
|         3 | Failed    | 2020-06-07 14:04:00 |
+-----------+-----------+---------------------+

我怀疑我需要在某处使用 Case 语句来获得此输出,但我不知道如何。请帮忙。

【问题讨论】:

  • 你能告诉我们你到目前为止做了什么吗?另外请你标记你的数据库吗?
  • @VBoka 我还没有成功。我正在使用 postgresql
  • 嗨@DenisKudriavtsev 请也检查一下:stackoverflow.com/help/someone-answers

标签: sql postgresql group-by greatest-n-per-group


【解决方案1】:

你可以使用distinct on:

select distinct on (record_id) t.*
from t
order by (case when status <> 'Completed' then 1 else 2 end),
         date desc;

【讨论】:

    【解决方案2】:

    不确定这是否是您正在寻找的,以及它是否正在完全运行。

    select report_id,
        case when q.failed_sum > 0 then 'Failed'
             when q.running_sum > 0 then 'Running'
            else  'Completed'
        end,
        max(date)
        from table inner join
            (
                select report_id, 
                sum(case when status = 'Failed' then 1 end) as failed_sum,
                sum(case when status = 'Running' then 1 end) as running_sum,
                sum(case when status = 'Completed' then 1 end)as completed_sum
                from table 
                group by report_id
            )q on report_id = q.report_id
        where status = (case when failed_sum > 0 then 'Failed'
            else when running_sum > 0 then 'Running'
            else then 'Completed'
        end) 
        group by report_id
    

    【讨论】:

      【解决方案3】:

      您可以使用 STRING_AGG 将状态列的文本组合成一个字符串,并检查该字符串是否包含“正在运行”或“失败”

      select report_id, 
      case when STRING_AGG(status, '') like '%Running%' then 'Running'
      when STRING_AGG(status, '') like '%Failed%' then 'Failed'
      else 'Completed' end Status,
      max(date) Date
      from abc
      group by report_id
      

      【讨论】:

      • 谢谢!我发现您的解决方案最短且最适合我
      【解决方案4】:

      您可以尝试使用row_number()

      select * from
      (
      select report_id,status,date, row_number() over(partition by report_id order by 
      case when status in ('Running','Failed') then 1 else 2 end asc,Date desc) as rn
      from tablename
      )A where rn=1
      

      【讨论】:

        【解决方案5】:

        查看您的样本,您似乎需要每个报告的第一状态(基于日期)

        select m.* 
        from my_table m
        inner join (
            select Report_id,  min(date) min_date
            from my_table  
            group by Report_id
        ) t on t.Report_id = m. and t.min_date  = m.date
        

        【讨论】:

        • 不,这行不通。如果一切都完成了,我需要最后一个日期。如果状态是 Failed 或 Running 比我需要它的日期,它可以有任何日期,所以最小日期在这里不起作用
        • @DenisKudriavtsev 我们不在您的数据库和您的脑海中.. 我们唯一能知道的就是您的问题和数据样本。你应该更好地解释你的需求..在你的评论中你说“如果一切都完成了比我需要最后一个日期,”..你report_id = 2这与你的样本结果不一致
        猜你喜欢
        • 2020-04-01
        • 2017-03-22
        • 1970-01-01
        • 2022-01-15
        • 2013-11-19
        • 1970-01-01
        • 1970-01-01
        • 2021-03-15
        • 1970-01-01
        相关资源
        最近更新 更多