如果满足条件,如何编写SQL以返回一行,如果不满足则返回另一行

时间:2019-04-19 08:51:10

标签: sql postgresql

我一直在写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

对于Math,既有形式考试又有模拟考试,因此需要返回最新的形式考试;对于Science,只有模拟考试,因此应返回模拟考试。

出于其他考虑,需要在一条SQL语句中实现它。

3 个答案:

答案 0 :(得分:2)

这是Kaushik的方法的微小变化。 class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::enableForeignKeyConstraints(); Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } } 是必经之路,但我将逻辑写为:

  ngAfterViewInit(): void {
   if(this.el.nativeElement.value==null||this.el.nativeElement.value==""){
        this.el.nativeElement.setAttribute("custom-attribute", "false");
    }else{
        this.el.nativeElement.setAttribute("custom-attribute", "true")
    } 
}

distinct on为分组中的每组值(括号中的内容)返回一行。该行是由select distinct on (name, class) t.* from t order by name, class, (mode = 'formal') desc, exam_time desc; 确定的第一行。

答案 1 :(得分:1)

在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

答案 2 :(得分:0)

我们可以在此处使用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一起使用的分区逻辑将所有正式记录放在所有模拟记录之前。这意味着仅在根本没有此类最新正式记录的情况下,才会返回模拟记录。