Обнаружение совпадающих диапазонов дат из одной таблицы
У меня есть таблица со следующими данными
PKey Start End Type
==== ===== === ====
01 01/01/2010 14/01/2010 S
02 15/01/2010 31/01/2010 S
03 05/01/2010 06/01/2010 A
И хочу получить следующие результаты
PKey Start End Type
==== ===== === ====
01 01/01/2010 14/01/2010 S
03 05/01/2010 06/01/2010 A
Любые идеи о том, с чего начать? Многое из чтения, которое я сделал, предполагает, что мне нужно создавать записи и каждый день и присоединяться к совпадающим дням, это единственный способ?
Ответы
Ответ 1
Если у вас уже есть записи за каждый день, который должен работать, но если вы не накладные расходы значительны, и если этот запрос используется часто, это повлияет на производительность.
Если данные находятся в этом формате, вы можете обнаружить перекрытия с помощью простой арифметики дат, поскольку перекрытие - это просто один интервал, начинающийся после заданного интервала, но до того, как данное будет завершено, что-то вроде
select dr1.* from date_ranges dr1
inner join date_ranges dr2
on dr2.start > dr1.start -- start after dr1 is started
and dr2.start < dr1.end -- start before dr1 is finished
Если вам нужна специальная обработка для интервала, который полностью находится в пределах другого интервала, или вам нужно слить интервалы, т.е.
PKey Start End Type
==== ===== === ====
01 01/01/2010 20/01/2010 S
02 15/01/2010 31/01/2010 S
получая
Start End Type
===== === ====
01/01/2010 31/01/2010 S
вам понадобится более сложный расчет.
В моем опыте с такими проблемами, как только вы получите, как делать вычисления вручную, легко передать его в SQL:)
Ответ 2
Может быть:
SELECT A.PKey, A.Start, A.End, A.Type
FROM calendar AS A, calendar AS B
WHERE (p.pkey<>a.pkey
AND b.start>=a.start
AND b.end<=a.end)
OR (b.pkey<>a.pkey
AND b.start<=a.start
AND b.end>=a.end)
Ответ 3
Когда мне нужно было сравнить два временных интервала в SQL для перекрытия, вот четыре сценария, о которых я мог подумать:
- Начало Span1 начинается между запуском Span2 и концом Span2
- Конец Span1 находится между запуском Span2 и концом Span2
- Начало и конец Span1 - между запуском Span2 и концом Span2
- Начало и конец Span2 находятся как между запуском Span1, так и концом Span1
Вот оператор OR, который я создал для захвата этих сценариев (в моем случае Oracle SQL):
and (
s1.start between s2.start and s2.end
OR
s1.end between s2.start and s2.end
OR
s2.start between s1.start and s1.end
)
Ответ 4
select A.*
from MyTable A
inner join MyTable B
on (B.start <= A.end)
and (B.end >= A.start)
или что-то в этом роде (предполагая, что даты не являются нулевыми, а равные даты считаются перекрытием).
Ответ 5
Я должен был сделать очень похожее дело, чтобы остановить повторный праздник, который был введен в таблицу. он был в доступе и написан на соблазнительный вход, поэтому пришлось запросить его в VBA SQL:
stCommandText = "SELECT " _
& "* " _
& "FROM " _
& "TableName a, " _
& "TableName b " _
& "WHERE " _
& "a.ID = b.ID " _
& "AND a.Startdate >= b.Startdate AND a.StartDate <= b.EndDate " _
& "AND a.AutoNo <> b.AutoNo "
Ответ 6
Мы все давно нуждались в таком перекрывающемся предикате в наших запросах, и я думаю, что нашел очень простое решение здесь.
В моем приложении, например, у меня есть политики, имеющие один и тот же номер политики, но, возможно, описание политики меняется с одного финансового года на следующий. Когда пользователь вводит новую запись (тот же номер политики, другое описание политики), мне нужен способ узнать, существует ли эта политика уже для указанного временного диапазона. Если новые даты эффективности политики/срока действия совпадают с тем, что уже есть в базе данных, мне нужно было сделать ошибку и сообщить пользователю, почему их ввод неверен.
Чтобы сделать это, я пошел со следующим утверждением предиката:
AND @_expiration >= EffectiveDate AND ExpirationDate >= @_effective
Надеюсь, кто-то найдет это полезным, как я.
Ответ 7
В MySQL вам в основном нужно:
SELECT COUNT(*)
FROM date_ranges AS A, date_ranges AS B
WHERE A.id <> B.id
AND A.id > B.id
AND A.end_at > B.start_at
AND B.end_at > A.start_at
>
во втором и третьем операторах можно заменить на >=
, чтобы следовать включению соответствия.
Этот раздел связан с "Алленной алгеброй Аллена", и есть еще некоторые сведения об этом можно найти по этим ссылкам:
Ответ 8
BTW - Если у вас нет уникального идентификатора, против ваших дат вы можете сделать это, оракул.. FYI
with date_ranges
as
(
SELECT
rownum as pkey,
date_ranges.*
FROM date_ranges
)
select
dr1.*
from
date_ranges dr1 , date_ranges dr2
where dr1.pkey > dr2.pkey
AND dr1.end_dt >= dr2.start_dt
AND dr2.end_dt >= dr1.start_dt
Ответ 9
Sql = 'SELECT task_id
, task_start_date
, task_due_date
FROM (wba_task
) WHERE (task_start_date
<= "2016-07-13" AND task_due_date
>= "2016-07- 25" ) ИЛИ (task_due_date
МЕЖДУ "2016-07-13" и "2016-07-25" ) ';
Запрос Codeigniter ниже.
$fromdaysDate="2016-07-13";//changed date
$todaysDate="2016-07-25";//changed date
$this->db->select('task_id,task_start_date, task_due_date');
$this->db->where('task_start_date <="'.date('Y-m-d', strtotime($fromdaysDate)).'"');
$this->db->where('task_due_date >="'.date('Y-m-d', strtotime($todaysDate)).'"');
$this->db->or_where('task_due_date BETWEEN "'. date('Y-m-d', strtotime($fromdaysDate)). '" and "'. date('Y-m-d', strtotime($todaysDate)).'"');
$alltask=$this->db->get('wba_task')->result_array();
echo $this->db->last_query();
получить всю базу данных данных перекрытия.... ![введите описание изображения здесь]()