2015-11-03 2 views
2

Я хотел бы найти все диапазоны дат в таблице с данными и столбцом даты. Диапазон дат будет разбит, если данные не будут в день.Найти диапазоны дат в таблице mysql

, например, если таблица содержит данные между 1-1-2015 до 3-3-2015

и нет никаких данных, в дни 5-1-2015 и 6-2-2015

затем Я хотел бы получать диапазоны дат

1-1-2015 until 4-1-2015 

6-1-2015 until 5-2-2015 

7-2-2015 until 3-3-2015 

есть ли способ сделать это с помощью запроса mysql?

+0

может сделать это двумя способами (в SQL): с помощью таблицы календаря (если у вас есть один) или с использованием дешевого симулятора таблицы календаря с жестко закодированными кросс-соединениями на цифрах. или вы можете сделать это в своем коде приложения – amdixon

+0

, так что нет необходимости непосредственно выполнять работу? – vagelis

+0

не встроенная вещь.пример ниже показывает, как имитировать таблицу календаря для этого – amdixon

ответ

1

план

  • перекрестное соединение цифры вместе, чтобы имитировать настольный календарь
  • покинул присоединиться календарь DataSource и определить, когда дата нет
  • порядок над выше, используя SQL переменные RGN и границы
  • агрегат над rgn и граница для получения каждой области

установки

create table somedates 
(
    id integer primary key not null, 
    vdate date not null 
); 

drop view if exists digits_v; 
create view digits_v 
as 
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 
; 

insert into somedates 
(id, vdate) 
select @id := @id + 1 as id, date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) as vdate 
from digits_v a2 
cross join digits_v a1 
cross join digits_v a0 
cross join (select @id := 0) params 
where date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) <= date('2015-03-03') 
and date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) not in 
(
    '2015-01-05', 
    '2015-02-06' 
) 
; 

запрос

select rgn, min(boundary) `from`, max(boundary) `to` 
from 
(
select active.aday, active.present, 
@rgn := if(active.present, 
      if(@boundary := active.aday, @rgn, @rgn), 
      if(@boundary := null, @rgn + 1, @rgn + 1)) as rgn, 
@boundary as boundary 
from 
(
select date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) as aday, 
case when sd.id is not null then true 
    else false 
end as present 
from digits_v a2 
cross join digits_v a1 
cross join digits_v a0 
left join somedates sd 
on sd.vdate = date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) 
where date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) <= date('2015-03-03') 
and date_add('2015-01-01', interval a2.n * 100 + a1.n * 10 + a0.n day) >= date('2015-01-01') 
) active 
cross join (select @rgn := 0, @boundary := date('2015-01-01')) params 
order by active.aday 
) boundaries 
group by rgn 
having `from` is not null 
; 

выход

+-----+------------+------------+ 
| rgn | from |  to  | 
+-----+------------+------------+ 
| 0 | 2015-01-01 | 2015-01-04 | 
| 1 | 2015-01-06 | 2015-02-05 | 
| 2 | 2015-02-07 | 2015-03-03 | 
+-----+------------+------------+ 

sqlfiddle


ссылка

+0

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

+0

возможно - как? – amdixon

+0

Давайте подождем и посмотрим. – Strawberry

0

По вашему описанию, у вас есть набор данных примерно так ...

CREATE TABLE my_table 
(data CHAR(2) NULL 
,date DATE NOT NULL PRIMARY KEY); 

INSERT INTO my_table VALUES 
('AB','2015-01-01'), 
('AB','2015-01-02'), 
('AB','2015-01-03'), 
('AB','2015-01-04'), 
(NULL,'2015-01-05'), 
('AB','2015-01-06'), 
('...etc.'' 

Если предположить, что это правильно, то запрос может выглядеть примерно так ...

SELECT a.date start 
    , MIN(c.date) end 
    FROM my_table a 
    LEFT 
    JOIN my_table b 
    ON b.date = a.date - INTERVAL 1 DAY 
    AND b.data IS NOT NULL 
    LEFT 
    JOIN my_table c 
    ON c.date >= a.date 
    AND c.data IS NOT NULL 
    LEFT 
    JOIN my_table d 
    ON d.date = c.date + INTERVAL 1 DAY 
    AND d.data IS NOT NULL 
WHERE b.date IS NULL 
    AND c.date IS NOT NULL 
    AND d.date IS NULL 
    AND a.data IS NOT NULL 
GROUP 
    BY a.date; 
Смежные вопросы