Как найти пропущенные строки (даты) в таблице MySQL? - PullRequest
3 голосов
/ 02 апреля 2011

Я пробовал несколько тем, подобных этой: Как найти отсутствующие строки данных с помощью SQL? здесь, но я не мог заставить это работать в моей ситуации.

У меня есть таблица с именем posts в MySQL, в которую я каждый день сохраняю дневники пользователей. Иногда пользователи забывают написать сообщение на один день, и я хочу, чтобы они могли отправить его позже. Таким образом, структуры БД, как это:

date           userid
2011-10-01     1
2011-10-02     1
(missing)
2011-10-04     1
2011-10-05     1
(missing)
2011-10-07     1

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

Как я могу это сделать? Спасибо.

Ответы [ 3 ]

5 голосов
/ 02 апреля 2011

Самый простой способ найти пропущенные даты - использовать таблицу календаря.Я разместил код для создания и заполнения таблицы календаря для PostgreSQL ;Вы должны иметь возможность адаптировать его без каких-либо проблем.

С установленной таблицей календаря ваш запрос довольно прост и легок для понимания.Чтобы найти недостающие даты на октябрь 2011 года, вы должны использовать что-то вроде этого.(Догадываясь за вашей таблицей "сообщений".)

select c.cal_date
from calendar c
left join posts p on (c.cal_date = p.date)
where p.date is null
  and c.cal_date between '2011-10-01' and '2011-10-31'
  and p.userid = 1
order by c.cal_date
3 голосов
/ 02 апреля 2011

Эти типы запросов легче всего решить, если у вас есть таблица дат. В вашей БД запустите этот пакет разово, чтобы создать заполненную таблицу дат.

DROP PROCEDURE IF EXISTS FillDateTable;

delimiter //
CREATE PROCEDURE FillDateTable()
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN
  drop table if exists datetable;
  create table datetable (thedate datetime primary key, isweekday smallint);

  SET @x := date('2000-01-01');
  REPEAT 
    insert into datetable (thedate, isweekday) SELECT @x, case when dayofweek(@x) in (1,7) then 0 else 1 end;
    SET @x := date_add(@x, interval 1 day);
    UNTIL @x >= '2030-12-31' END REPEAT;
END//
delimiter ;

CALL FillDateTable;

Тогда вы можете просто использовать обычный LEFT JOIN

SELECT thedate
FROM datetable
LEFT JOIN posts on posts.date = datetable.thedate
WHERE posts.date IS NULL

Конечно, вы не хотите, чтобы все «пропущенные» даты были с 2000 по 2030 год. Ограничьте его минимальными и максимальными датами в таблице сообщений (для пользователя), т.е.

SELECT thedate
FROM datetable
INNER JOIN (select min(date) postStart, max(date) postEnd
            FROM posts
            where userid=123) p on datetable.thedate BETWEEN p.postStart and p.postEnd
LEFT JOIN posts on posts.date = datetable.thedate
WHERE posts.date IS NULL
1 голос
/ 02 апреля 2011

Вы можете автоматически вводить пустое сообщение каждый раз (конец дня) с нулевыми заголовками, нулевым содержимым, но с фактической датой. Затем, если пользователь хочет добавить сообщение за предыдущий день, отобразите все сообщения с пустыми заголовками и содержимым и обновите выбранное сообщение.

Это не должно быть проблемой с пространством, если они пишут больше, чем скучают. Например, если они пишут 4 дня и пропускают 1.

Кроме того, вы должны запустить скрипт и удалить записи с нулевыми заголовками, нулевым содержимым и датой старше X дней. Если они не добавили недостающий пост в течение X дней, они, вероятно, никогда этого не сделают.

Я прошу прощения, если мое решение тривиально / слишком абстрактно.

...