简体   繁体   English

SQL 查询,select 顶部结果或底部结果取决于行是否存在

[英]SQL query, select top result or bottom result depending on if row exists

I need to select rows:我需要 select 行:

One for each distinct centerid and studentid每个不同的 centerid 和 studentid 一个
The column status is not 'D' and the oldest one (I use autoincremented id ).列状态不是 'D' 和最旧的(我使用自动增量id )。
If no such row exists, find the newest column with createdDate today and status='D'.如果不存在这样的行,则查找今天的 createdDate 和 status='D' 的最新列。
No row for that centerid, studentid, if no such row exists.如果不存在这样的行,则没有该 centerid、studentid 的行。

Below is the query I'm currently using:以下是我目前正在使用的查询:

SELECT *
FROM DailyJournals as DJ
WHERE IFNULL(
        (SELECT id FROM DailyJournals AS x WHERE DJ.studentid = x.studentid AND DJ.centerid = x.centerid
          AND NOT status = 'D' ORDER BY id LIMIT 1),
        (SELECT id FROM DailyJournals AS x WHERE DJ.studentid = x.studentid AND DJ.centerid = x.centerid
          AND createdDate = DATE(NOW()) ORDER BY id DESC LIMIT 1)
      ) = DJ.id;

Trying to find the best way to add indexes and structure the query and DB to keep this reasonably optimized while keeping it simple.试图找到添加索引和构建查询和数据库的最佳方法,以在保持简单的同时保持合理优化。 Load is very small for now, and the table gets pruned, so performance isn't currently an issue.目前负载非常小,并且表被修剪,因此性能目前不是问题。

MariaDB 10.4 MariaDB 10.4
centerid and studentid are 3 character alphanumeric strings. centerid 和 studentid 是 3 个字符的字母数字字符串。 id is autoincremented indexed primary key. id 是自动递增的索引主键。 createdDate is a date string for when the row was created. createdDate 是创建行时的日期字符串。

Some additional information:一些附加信息:

(There are only a few possible values for column status and it's a 2 character string) which I've set up an indexed virtual boolean column for (done=0 or done=1) (列状态只有几个可能的值,它是一个 2 个字符的字符串)我已经为(done=0 或 done=1)设置了一个索引虚拟 boolean 列

alter table DailyJournals add column `done` bool as (status='D');
create index done on DailyJournals(done);

You can try using row_number() :您可以尝试使用row_number()

select dj.*
from (select dj.*,
             row_number() over (partition by centerid, studentid
                                order by (status <> 'D') desc,
                                         (case when status <> 'D' then id end) desc,
                                         id asc
                               ) as seqnum
      from dailyjournals dj
     ) dj
where seqnum = 1;

EDIT:编辑:

From a performance perspective, probably the best you can do is a computed column with an index.从性能的角度来看,您能做的最好的事情可能是带有索引的计算列。

alter table DailyJournals
    add column magic_d_id int as 
        (status = 'D' then id else - id end);

create index dailyjournals_magic_d_id on DailyJournals(centerid, dataid, magic_d_id);

You can try row_number() :您可以尝试row_number()

row_number() over (partition by centerid, studentid order by magic_d_id)

I'm not sure if that will use the index.我不确定这是否会使用索引。 You can also use:您还可以使用:

select dj.*
from dailyjournals dj
where dj.magic_d_id = (select dj2.magic_d_id
                       from dailyjournals dj2
                       where dj2.centerid = dj.centerid and
                             dj2.studentid = dj.studentid and
                       order by dj2.magic_d_id
                       limit 1
                      );

This assumes that id is an integer and never negative.这假设id是 integer 并且永远不会是负数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM