Генерация данных для диапазона дат, включая те, которые отсутствуют в данных - PullRequest
2 голосов
/ 26 июля 2011

Вот моя структура таблицы и данные:

CREATE TABLE event (
    EventID INT(11) NOT NULL AUTO_INCREMENT,
    EventDate DATETIME DEFAULT NULL,
    Description VARCHAR(50) DEFAULT NULL,
    PRIMARY KEY (EventID)
);

INSERT INTO event (EventID, EventDate, Description) VALUES
    (1, '2011-01-01 00:00:00', 'Event 1'),
    (2, '2011-03-01 00:00:00', 'Event 2'),
    (3, '2011-06-01 00:00:00', 'Event 3'),
    (4, '2011-09-01 00:00:00', 'Event 4');

И этот запрос и вывод:

SELECT *
FROM EVENT
WHERE EventDate BETWEEN '2011-02-01' AND '2011-03-31'
+---------+---------------------+-------------+
| EventID | EventDate           | Description |
+---------+---------------------+-------------+
|       2 | 2011-03-01 00:00:00 | Event 2     |
+---------+---------------------+-------------+
1 row in set (0.00 sec)

Я хочу вставить пустые даты в результат, например так:

+---------+---------------------+-------------+
| EventID | EventDate           | Description |
+---------+---------------------+-------------+
| NULL    | 2011-02-01 00:00:00 |  NULL       |
| NULL    | 2011-02-02 00:00:00 |  NULL       |
| NULL    | 2011-02-03 00:00:00 |  NULL       |
∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨
∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧
| NULL    | 2011-02-28 00:00:00 |  NULL       |
|       2 | 2011-03-01 00:00:00 |  Event 2    |
| NULL    | 2011-03-02 00:00:00 |  NULL       |
∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨
∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧
| NULL    | 2011-03-31 00:00:00 |  NULL       |
+---------+---------------------+-------------+

Вывод должен содержать 59 строк: 28 для февраля и 31 для марта.

Я хочу избежать жесткого кодирования;вместо этого мне нужно очень гибкое решение, которое адаптируется к указанным датам.

Ответы [ 3 ]

2 голосов
/ 26 июля 2011

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

create table calendar (
    cal_date date primary key
);

Вы можете использовать электронную таблицу или SQL для ее заполнения. Внешнее объединение принесет даты, которых нет в ваших данных. Ограничьте разрешения с помощью GRANT и REVOKE и используйте все необходимые средства, чтобы убедиться, что даты, на которые вы рассчитываете попасть, действительно там. Я запускаю ежедневный отчет на своем сервере, который проверяет наличие n строк и проверяет самые ранние и самые поздние даты.

На некоторых платформах вы можете сгенерировать серию дат на лету и использовать их напрямую или в CTE. PostgreSQL имеет функции для этого; Я не знаю, делает ли MySQL. Их не сложно написать, хотя, если ты хочешь сделать свой собственный.

1 голос
/ 26 июля 2011

может быть, вам нужен сводный стол, посмотрите на это

схема сводной таблицы

имя: пивот столбцы: {i: тип данных int}

Populate

создать таблицу foo

схема foo

имя: foo столбец: значение типа данных varchar

insert into foo
values('0'),
values('1'),
values('2'),
values('3'),
values('4'),
values('5'),
values('6'),
values('7'),
values('8'),
values('9');

- insert 100 values
insert into pivot
select concat(a.value, a.value)
from foo a, foo b

- insert 1000 values
insert into pivot
select concat(a.value, b.value, c.value)
from foo a, foo b, foo c

ваш запрос

SELECT 
 Event.EventId,
 case when EventDate is null then DATE_ADD(periods.periodstart, INTERVAL auxtable.i DAY)
 else EventDate  end,
 Description

FROM
(
  select id, min(EventDate ) periodstart, max(EventDate) periodend,

  DATEDIFF(max(EventDate),min(EventDate )) as days
  FROM EVEN
  WHERE EventDate BETWEEN '2011-02-01' AND '2011-03-31'
) periods

inner join     

(
  select *
  from pivot
  where i >= 0 and i < 31 //max one month change with your needs
)auxtable
on auxtable.i < periods.days

left join Event
on Event.EventDate = DATE_ADD(periods.periodstart, INTERVAL auxtable.i DAY)
0 голосов
/ 26 июля 2011

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

  • использовать хранимую процедуру / функцию
  • сделать это в коде приложения, который выглядитдовольно прямолинейно
...