MySQL: выбрать строку только там, где у ближайшего к дате значения столбца - PullRequest
0 голосов
/ 29 июня 2019

Я хочу вернуть все строки, которые были общедоступными в мае (2019-05), поэтому, если строка была превращена в черновик (а не обратно в общедоступную) в любой точке до конца мая, я не хочу этого,Например:

id | post_id | status | date
-------------------------
 1 | 1       | draft  | 2019-03-25
 2 | 1       | public | 2019-04-02
 3 | 1       | draft  | 2019-05-25
 4 | 2       | draft  | 2019-03-10
 5 | 2       | public | 2019-04-01
 6 | 2       | draft  | 2019-06-01

Требуемый результат для вышеуказанного вернет post_id 2, поскольку его последнее изменение статуса до конца мая было public.

post_id 1 быловернуть в черновик до конца мая, чтобы он не был включен.

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

Ответы [ 2 ]

1 голос
/ 29 июня 2019

Вы, кажется, хотите статус по состоянию на 2019-05-31. Коррелированный подзапрос кажется самым простым решением:

select t.*
from t
where t.date = (select max(t2.date)
                from t t2
                where t2.post_id = t.post_id and
                      t2.date <= '2019-05-31'
               );

Чтобы получить общедоступные, просто добавьте условие WHERE:

select t.*
from t
where t.date = (select max(t2.date)
                from t t2
                where t2.post_id = t.post_id and
                      t2.date <= '2019-05-31'
               ) and
      t.status = 'public';

Для производительности вам нужен индекс на (post_id, date).

Вы также можете сформулировать это, используя JOIN:

select t.*
from t join
     (select t2.post_id, max(t2.date) as max_date
      from t t2
      where t2.date <= '2019-05-31'
      group by t2.post_id
     ) t2
     on t2.max_date = t.date
where t.status = 'public';

Я ожидаю, что коррелированный подзапрос будет иметь лучшую производительность с правильными индексами. Однако иногда MySQL меня удивляет.

0 голосов
/ 29 июня 2019

нам нужно определить, является ли

  1. статус каждого post_id равен public до месяца May (подзапрос с max (date)),
  2. любой post_id существует со статусом, не равным public в течение месяца May,
  3. , а затем исключить post_id, удовлетворяющий материи 2.

Итак, вы можете использовать:

select distinct t1.post_id
  from tab t1
where t1.post_id not in
    (
     select distinct t1.post_id
       from tab t1
       join
       (
        select post_id, max(date) as date
          from tab 
         where '2019-05-01'> date
         group by post_id ) t2
         on t1.post_id = t2.post_id 
      where t1.status != 'public' 
        and t1.date < '2019-06-01' 
        and t1.date > '2019-04-30'
);

+---------+
| POST_ID |
+---------+
|    2    |
+---------+

Демо

...