2013-09-28 3 views
2

У меня есть 2 столбца, одна - дата начала, а другая - дата окончания. Мне нужно найти каждый день между двумя датами.Найти даты между датой начала и датой окончания в mysql

Нужна она в другой таблице с двумя колонками, одно имя pno, которое относится к id pno в первой таблице, а другое - к датам между датой начала и датой окончания.

В качестве примера это может быть мой вклад

 
pno   startdate  end date 
p1   2012-12-03  2012-12-06  
p2   2013-01-05  2013-01-08 
p3   2013-01-15  2012-01-20 

, и это должно быть мой выход.

 
pno   dates 
---------- 
p01   2012-12-03 
p01   2012-12-04 
p01   2012-12-05 
p01   2012-12-06 
p02   2013-01-05 
p02   2013-01-06 
p02   2013-01-07 
p02   2013-01-08 
p03   2013-01-15 
... 

ответ

4

Вы можете сделать это, как этот

SELECT pno, startdate + INTERVAL q.n - 1 DAY dates 
    FROM table1 t CROSS JOIN 
(
    SELECT a.N + b.N * 10 + 1 n 
    FROM 
    (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a 
    ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b 
    ORDER BY n 
) q 
WHERE q.n - 1 <= DATEDIFF(enddate, startdate) 
ORDER BY pno, dates 

Подзапрос генерирует последовательность чисел от 1 до 100. Вы можете настроить его для ваших нужд (если охватывают даты различия более или менее чем за 100 дней) или полностью заменить его таблицей с сохраненными таблицами (числами), если вы выполняете много таких запросов.

Выход:

 
+------+------------+ 
| pno | dates  | 
+------+------------+ 
| p1 | 2012-12-03 | 
| p1 | 2012-12-04 | 
| p1 | 2012-12-05 | 
| p1 | 2012-12-06 | 
| p2 | 2013-01-05 | 
| p2 | 2013-01-06 | 
| p2 | 2013-01-07 | 
| p2 | 2013-01-08 | 
| p3 | 2013-01-15 | 
| p3 | 2013-01-16 | 
| p3 | 2013-01-17 | 
| p3 | 2013-01-18 | 
| p3 | 2013-01-19 | 
| p3 | 2013-01-20 | 
+------+------------+ 

Вот SQLFiddle демо


UPDATE: Для создания и заполнения PERSISTED Tally таблица использования

CREATE TABLE tally (n INT NOT NULL PRIMARY KEY); 

INSERT INTO tally (n) 
SELECT a.n + b.n * 10 + c.n * 100 + d.n * 1000 + 1 n 
FROM 
(SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a 
,(SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b 
,(SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) c 
,(SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) d 
ORDER BY n; 

Y ou'll будет в последовательности таблиц таблицы от 1 до 10000. Это позволит вам работать с диапазонами дат, которые охватывают более 27 лет.

Теперь запрос сводится к

SELECT pno, startdate + INTERVAL q.n - 1 DAY dates 
    FROM table1 t CROSS JOIN tally q 
WHERE q.n - 1 <= DATEDIFF(enddate, startdate) 
ORDER BY pno, dates 

Вот SQLFiddle демо

+0

для дат с пролетом более 2-х лет – user2825758

+0

@ user2825758 См обновленный ответ и sqlfiddle пример. Создайте таблицу постоянных таблиц (чисел) с предоставленным скриптом и используйте их. ИМХО это самый быстрый и общий способ ** работать с диапазонами дат. Любой другой подход потребует использовать хранимую процедуру для использования циклов и будет медленнее и менее гибким. – peterm

+0

@ user2825758 Если вы чувствуете, что ответ был полезным, рассмотрите ** [accept] (http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) ** it , – peterm

Смежные вопросы