【问题标题】:How to write a SQL to return a row if condition met, and return another row if not如何编写 SQL 以在条件满足时返回一行,如果不满足则返回另一行
【发布时间】:2019-04-24 09:34:17
【问题描述】:

我一直在写一个 SQL 查询,这个函数类似于返回学生一个月内的最新正式考试成绩,或者如果学生没有正式考试,则返回最新的模拟考试成绩。

例如,这是一个保存考试成绩的表格,“模式”列用于正式考试或模拟考试。

name          class        mode      score   exam_time
Alice         Math         mock      92      2019-03-21 10:00:00
Alice         Math         formal    88      2019-03-18 10:00:00
Alice         Math         formal    95      2019-03-07 10:00:00
Alice         Science      mock      89      2019-03-13 14:00:00
Bob           Math         mock      96      2019-03-21 10:00:00
Bob           Math         formal    90      2019-03-18 10:00:00
Bob           Math         formal    95      2019-03-07 10:00:00
Bob           Science      mock      98      2019-03-13 14:00:00

需要查询结果为:

Alice    Math    formal    88     2019-03-18 10:00:00
Alice    Science mock      89     2019-03-13 14:00:00
Bob      Math    formal    90     2019-03-18 10:00:00
Bob      Science mock      98     2019-03-13 14:00:00

数学有正式考试和模拟考试,所以需要返回最新的正式考试,科学只有模拟考试,所以返回模拟考试。

因为其他考虑,需要在一条SQL语句中实现。

【问题讨论】:

  • 抱歉打错字了,应该是“成就”... //hammerself
  • 你会edit the post 修复它吗? :-)

标签: sql postgresql


【解决方案1】:

这是 Kaushik 方法的轻微变化。 distinct on 是要走的路,但我会把逻辑写成:

select distinct on (name, class) t.*
from t 
order by name, class, (mode = 'formal') desc, exam_time desc;

distinct on 为分组中的每组值返回一行(括号中的内容)。该行是由order by 确定的第一行。

【讨论】:

  • 非常感谢“distinct on”子句,太棒了!
【解决方案2】:

在 Postgres 中,我更喜欢 DISTINCT ON 来获得每个组的最高记录。它的性能稍好一些。

select DISTINCT ON (name,class) t.*
   from  t ORDER BY name,class,
    case when mode = 'formal' 
  then 0 else 1 end,exam_time desc ;

DEMO

【讨论】:

    【解决方案3】:

    我们可以在这里使用row_number

    select name, class, mode, score, exam_time
    from
    (
        select t.*, row_number() over (partition by name, class
                                       order by case when mode = 'formal' then 0 else 1 end,
                                                date_trunc('month', exam_time) desc) rn
        from your_table t
    ) t
    where rn = 1;
    

    上面使用row_number 的分区逻辑将所有正式记录放在所有模拟记录之前。这意味着只有在根本没有这样的最新正式记录时才会返回模拟记录。

    【讨论】:

      猜你喜欢
      • 2010-11-13
      • 1970-01-01
      • 2014-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多