SQL запрос, выберите верхний результат или нижний результат в зависимости от того, существует ли строка - PullRequest
0 голосов
/ 27 апреля 2020

Мне нужно выбрать строки:

Одна для каждого отдельного centerid и studentid
Статус столбца не 'D', а самый старый (я использую автоинкременту id).
Если такой строки не существует, найдите новейший столбец с созданной сегодня и status = 'D'.
Нет строки для этого centerid, студента, если такой строки не существует.

Ниже приведен запрос, который я сейчас использую:

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;

Попытка найти наилучший способ добавления индексов и структурирования запроса и БД, чтобы обеспечить его разумную оптимизацию при сохранении его простоты. На данный момент загрузка очень мала, и таблица сокращается, поэтому производительность в настоящее время не является проблемой.

MariaDB 10.4
centerid и studentid - это 3-символьные строки alphanumeri c. id - автоинкрементный индексированный первичный ключ. createDate - строка даты, когда строка была создана.

Некоторая дополнительная информация:

(Есть только несколько возможных значений для статуса столбца, и это строка из 2 символов), которая Я настроил индексированный виртуальный логический столбец для (done = 0 или done = 1)

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

1 Ответ

1 голос
/ 27 апреля 2020

Вы можете попробовать использовать 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;

РЕДАКТИРОВАТЬ:

С точки зрения производительности, вероятно, лучшее, что вы можете сделать, - это вычисляемый столбец с индексом.

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);

Вы можете попробовать row_number():

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

Я не уверен, что это будет использовать индекс. Вы также можете использовать:

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
                      );

Предполагается, что id является целым числом и никогда не бывает отрицательным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...