SQL-запрос, который возвращает все даты, не использованные в таблице - PullRequest
3 голосов
/ 30 декабря 2010

Допустим, у меня есть несколько записей, которые выглядят так:

2011-01-01 Cat
2011-01-02 Dog
2011-01-04 Horse
2011-01-06 Lion

Как создать запрос, который будет возвращать 2011-01-03 и 2011-01-05, то есть неиспользованные даты. Я отправляю блоги в будущее и хочу запрос, который покажет мне дни, когда я еще ничего не публиковал. Было бы смотреть с текущей даты на 2 недели в будущее.

Обновление:

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

CREATE PROCEDURE MISSING_DATES()
BEGIN
    CREATE TABLE TEMPORARY DATES (FUTURE DATETIME NULL)
    INSERT INTO DATES (FUTURE) VALUES (CURDATE())
    INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 1 DAY))
    ...
    INSERT INTO DATES (FUTURE) VALUES (ADDDATE(CURDATE(), INTERVAL 14 DAY))

    SELECT FUTURE FROM DATES WHERE FUTURE NOT IN (SELECT POSTDATE FROM POSTS)

    DROP TABLE TEMPORARY DATES
END 

Я думаю, что просто невозможно выбрать отсутствие данных.

Ответы [ 4 ]

4 голосов
/ 10 сентября 2012

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

Итак, предложение @ BenHoffstein поддерживать постоянную таблицу дат - хорошая.

Если не считать этого, вы можете динамически создать этот диапазон дат с помощью таблицы целых чисел .Предполагая, что таблица integers имеет столбец i с номерами не менее 0 - 13, а столбец даты в вашей таблице называется datestamp:

   SELECT candidate_date AS missing
     FROM (SELECT CURRENT_DATE + INTERVAL i DAY AS candidate_date
             FROM integers
            WHERE i < 14) AS next_two_weeks
LEFT JOIN my_table ON candidate_date = datestamp
    WHERE datestamp is NULL;
4 голосов
/ 30 декабря 2010

Одним из решений было бы создание отдельной таблицы с одним столбцом для хранения всех дат от настоящего момента до вечности (или всякий раз, когда вы ожидаете прекратить вести блог). Например:

CREATE TABLE Dates (dt DATE);
INSERT INTO Dates VALUES ('2011-01-01');
INSERT INTO Dates VALUES ('2011-01-02');
...etc...
INSERT INTO Dates VALUES ('2099-12-31');

После настройки этой справочной таблицы вы можете просто выполнить внешнее объединение, чтобы определить неиспользованные даты следующим образом:

SELECT d.dt 
FROM Dates d LEFT JOIN Blogs b ON d.dt = b.dt 
WHERE b.dt IS NULL

Если вы хотите ограничить поиск двумя неделями в будущем, вы можете добавить это в предложение WHERE:

AND d.dt BETWEEN NOW() AND ADDDATE(NOW(), INTERVAL 14 DAY)
0 голосов
/ 30 декабря 2010

Способ извлечения строк из базы данных MySQL - через SELECT.Таким образом, вы не можете выбрать строки, которые не существуют.

Я бы заполнил таблицу блога всеми возможными датами (в течение года, затем повторите процесс)

 create table blog (
    thedate date not null,
    thetext text null,
    primary key (thedate));

, выполнивцикл для создания всех записей дат за 2011 год (с использованием программы, например, $ mydate - это дата, которую вы хотите вставить)

  insert IGNORE into blog (thedate,thetext) values ($mydate, null);

(ключевое слово IGNORE не создает ошибку (дата является первичным ключом), еслидата уже существует)Затем вы обычно вводите значения

  insert into blog (thedate,thetext) values ($mydate, "newtext") 
  on duplicate key update thetext="newtext";

Наконец, чтобы выбрать пустые записи, вам просто нужно

  select thedate from blog where thetext is null;
0 голосов
/ 30 декабря 2010

Вам, вероятно, не понравится это:

select '2011-01-03', count(*) from TABLE where postdate='2011-01-03' 
  having count(*)=0 union
select '2011-01-04', count(*) from TABLE where postdate='2011-01-04' 
  having count(*)=0 union
select '2011-01-05', count(*) from TABLE where postdate='2011-01-05' 
  having count(*)=0 union
... repeat for 2 weeks

OR

создайте таблицу со всеми днями в 2011 году, затем выполните левое соединение, как

select a.days_2011
from all_days_2011
left join TABLE on a.days_2011=TABLE.postdate
where a.days_2011 between date(now()) and date(date_add(now(), interval 2 week))
and TABLE.postdate is null;
...