|
Запросом выделить пересечения интервалов времени в отдельные интервалы | ☑ | ||
---|---|---|---|---|
0
PCcomCat
08.06.17
✎
13:49
|
Доброго времени!
Прошу помощи. Возможно ли ЗАПРОСОМ объединить интервалы с разбивкой при пересечении? Есть режим работы: 08:00 - 12:00 13:00 - 17:00 С учетом целых суток запросом получаю первые интервалы: 00:00 - 08:00 - нераб. время 08:00 - 12:00 - раб. время 12:00 - 13:00 - нераб. время 13:00 - 17:00 - раб. время 17:00 - 24:00 - нераб. время Есть вторые интервалы, в которые выполняются работы: 09:00 - 11:00 - 1-я работа 12:00 - 16:00 - 2-я работа Нужно объединить интервалы так, чтобы учесть их пересечение и выделить отдельным интервалом. В результате нужно получить: 00:00 - 08:00 - нераб. время 08:00 - 09:00 - раб. время 09:00 - 11:00 - раб. время (это 1-я работа) 11:00 - 12:00 - раб. время 12:00 - 13:00 - нераб. время (это 2-я работа) 13:00 - 16:00 - раб. время (это 2-я работа) 13:00 - 17:00 - раб. время 17:00 - 24:00 - нераб. время Поделитесь опытом, если такое выполняли. Заранее благодарю. |
|||
1
Cyberhawk
08.06.17
✎
13:56
|
||||
2
PCcomCat
08.06.17
✎
13:57
|
? ))
|
|||
3
Cyberhawk
08.06.17
✎
14:00
|
(2) Позови его в ветку
|
|||
4
PCcomCat
08.06.17
✎
14:01
|
Ildarovich ! ))
|
|||
5
cw014
08.06.17
✎
14:03
|
Порядок сначала по первой дате, потом по второй
|
|||
6
PCcomCat
08.06.17
✎
14:04
|
Есть, конечно, мысля вытащить интервалы без пересечений и интервалы с пересечением, затем интервалы с пересечением разделить на три таблицы: левое пересечение, внутреннее пересечение, правое пересечение.
Но может есть проще вариант?! А я не догоняю... |
|||
7
cw014
08.06.17
✎
14:05
|
(6) я тебе в (5) уже идею дал
|
|||
8
PCcomCat
08.06.17
✎
14:08
|
(7) Для меня она туманна... :(
|
|||
9
cw014
08.06.17
✎
14:09
|
Выбирай все периоды в запросе объединением. У тебя два поля "Время начала" и "Время окончания". Делай упорядочивание сначала по "Время начала" потом по "Время окончания"
|
|||
10
PCcomCat
08.06.17
✎
14:13
|
Сейчас у меня две разные таблицы. Я так понимаю, нужно слить их в одну? Думаю......
|
|||
11
Ildarovich
08.06.17
✎
15:50
|
Вот одно из возможных решений. Его суть - в условии пересечения отрезков для соединения таблиц
ВЫБРАТЬ
|
|||
12
PCcomCat
08.06.17
✎
16:20
|
Спасибо большое!!!
Правда теряю три интервала при таком соединении: 08:00 - 09:00 11:00 - 12:00 16:00 - 17:00 Мне почти удалось собрать методом в (6) - рюшечки остались. Но вашим методом красивее и проще. Потерянное добавлю самостоятельно. Еще раз спасибо!!!! |
|||
13
PCcomCat
08.06.17
✎
16:32
|
В (11) я могу получить интервалы пересечений и не участвовавшие в анализе пересечений интервалы.
Но всё-равно придется вытаскивать левый и правый интервалы не вошедшие в пересечение, но участвовавшие в анализе. |
|||
14
PCcomCat
08.06.17
✎
16:34
|
Окончательный вариант выложу.
|
|||
15
PCcomCat
08.06.17
✎
16:44
|
У меня получилось вот так самостоятельно дернуть интервалы:
ВЫБРАТЬ ЗагрузкаДней.ДатаКалендаря КАК ДатаКалендаря, "Пересечение" КАК Признак, ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ЗагрузкаДней.ВремяНачала ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяНачала КОНЕЦ КАК ВремяНачала, ВЫБОР КОГДА ЗагрузкаДней.ВремяОкончания <= ГрафикПоПроизводственномуКалендарю.ВремяОкончания ТОГДА ЗагрузкаДней.ВремяОкончания ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяОкончания КОНЕЦ КАК ВремяОкончания ИЗ ЗагрузкаДней КАК ЗагрузкаДней ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГрафикПоПроизводственномуКалендарю КАК ГрафикПоПроизводственномуКалендарю ПО ЗагрузкаДней.ДатаКалендаря = ГрафикПоПроизводственномуКалендарю.ДатаКалендаря И ЗагрузкаДней.ВремяНачала <= ГрафикПоПроизводственномуКалендарю.ВремяОкончания И ЗагрузкаДней.ВремяОкончания >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ГДЕ НЕ ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ЗагрузкаДней.ВремяНачала ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяНачала КОНЕЦ = ВЫБОР КОГДА ЗагрузкаДней.ВремяОкончания <= ГрафикПоПроизводственномуКалендарю.ВремяОкончания ТОГДА ЗагрузкаДней.ВремяОкончания ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяОкончания КОНЕЦ ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ЗагрузкаДней.ДатаКалендаря, "Левый интервал", ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ГрафикПоПроизводственномуКалендарю.ВремяНачала ИНАЧЕ ЗагрузкаДней.ВремяНачала КОНЕЦ, ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ЗагрузкаДней.ВремяНачала ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяНачала КОНЕЦ ИЗ ЗагрузкаДней КАК ЗагрузкаДней ВНУТРЕННЕЕ СОЕДИНЕНИЕ ГрафикПоПроизводственномуКалендарю КАК ГрафикПоПроизводственномуКалендарю ПО ЗагрузкаДней.ДатаКалендаря = ГрафикПоПроизводственномуКалендарю.ДатаКалендаря И ЗагрузкаДней.ВремяНачала <= ГрафикПоПроизводственномуКалендарю.ВремяОкончания И ЗагрузкаДней.ВремяОкончания >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ГДЕ НЕ ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ГрафикПоПроизводственномуКалендарю.ВремяНачала ИНАЧЕ ЗагрузкаДней.ВремяНачала КОНЕЦ = ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ЗагрузкаДней.ВремяНачала ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяНачала КОНЕЦ И НЕ ВЫБОР КОГДА ЗагрузкаДней.ВремяНачала >= ГрафикПоПроизводственномуКалендарю.ВремяНачала ТОГДА ЗагрузкаДней.ВремяНачала ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяНачала КОНЕЦ = ВЫБОР КОГДА ЗагрузкаДней.ВремяОкончания <= ГрафикПоПроизводственномуКалендарю.ВремяОкончания ТОГДА ЗагрузкаДней.ВремяОкончания ИНАЧЕ ГрафикПоПроизводственномуКалендарю.ВремяОкончания КОНЕЦ Так получаю пересечения и левые интервалы от пересечений. С правым вожусь. Если в "пересечении" поставить левое соединение, то получаю то же, что и в (11) - вот тут я затупила((. |
|||
16
Ildarovich
08.06.17
✎
22:42
|
(13) Понял, что в задаче также требуется найти незанятые никакими работами интервалы. Если двигаться в том же направлении, что и (11), то достаточно изменить две вещи:
1) добавить во вторую таблицу пустые промежутки: ОБЪЕДИНИТЬ ВСЕ
2) Упростить сам запрос, сделав соединение внутренним, поскольку пересечение после дополнения 1) будет всегда: ВЫБРАТЬ
Правда, тут "некрасивая" часть, связанная с определением интервалов дополнения (интервалов между интервалами), оставлена за скобками. Для определения интервалов дополнения их потребуется объединить с интервалами (0, 0), (23:59:59, 23:59:59), соединить эту таблицу с собой по неравенству, сгруппировать, найти интервалы (макс(слева), от) - получается довольно длинно, да еще повторить для первой и второй таблицы. |
|||
17
Ildarovich
08.06.17
✎
22:46
|
+(16) допустил две неточности: в 1) "2-я работа" заменить на "без работы", в 2) ЛЕВОЕ СОЕДИНЕНИЕ заменить на ВНУТРЕННЕЕ СОЕДИНЕНИЕ
|
|||
18
PCcomCat
08.06.17
✎
22:48
|
(17) Спасибо! Попробую разобраться. Пока пошла понятным путем: объединением с левыми и правыми интервалами.
|
|||
19
PCcomCat
08.06.17
✎
22:53
|
Плюс ко всему, приходится учитывать, что пересечение концов может совпадать, и при этом начало следующего интервала - это конец предыдущего, причем секунда в секунду.
Например: график работы 08:00 - 12:00 13:00 - 17:00 сами работы могут иметь интервалы: 09:00 - 12:00 12:00 - 16:00. Мысль понятна. Также для себя приятно, что двигаюсь в нужном направлении. |
|||
20
eryomin
09.06.17
✎
10:59
|
<Code>
ВЫБРАТЬ 8 КАК Начало, 12 КАК Окончание ПОМЕСТИТЬ ВТ_10 ОБЪЕДИНИТЬ ВЫБРАТЬ 13, 17 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_1.Начало КАК Начало, ВТ_1.Окончание КАК Окончание, ИСТИНА КАК Рабочее ПОМЕСТИТЬ ВТ_1 ИЗ ВТ_10 КАК ВТ_1 ОБЪЕДИНИТЬ ВЫБРАТЬ 0, МИНИМУМ(ВТ_1.Начало), ЛОЖЬ ИЗ ВТ_10 КАК ВТ_1 ИМЕЮЩИЕ МИНИМУМ(ВТ_1.Начало) > 0 ОБЪЕДИНИТЬ ВЫБРАТЬ МАКСИМУМ(ВТ_1.Окончание), 24, ЛОЖЬ ИЗ ВТ_10 КАК ВТ_1 ИМЕЮЩИЕ МАКСИМУМ(ВТ_1.Окончание) < 24 ОБЪЕДИНИТЬ ВЫБРАТЬ ВТ_1.Окончание, ВТ_11.Начало, ЛОЖЬ ИЗ ВТ_10 КАК ВТ_1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_10 КАК ВТ_11 ПО ВТ_1.Окончание < ВТ_11.Начало ЛЕВОЕ СОЕДИНЕНИЕ ВТ_10 КАК ВТ_12 ПО ВТ_1.Окончание < ВТ_12.Начало И (ВТ_12.Начало < ВТ_11.Начало) ГДЕ ВТ_12.Начало ЕСТЬ NULL ; //////////////////////////////////////////////////////////////////////////////// УНИЧТОЖИТЬ ВТ_10 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ 12 КАК Начало, 16 КАК Окончание ПОМЕСТИТЬ ВТ_20 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_2.Начало КАК Начало, ВТ_2.Окончание КАК Окончание, ИСТИНА КАК Рабочее ПОМЕСТИТЬ ВТ_2 ИЗ ВТ_20 КАК ВТ_2 ОБЪЕДИНИТЬ ВЫБРАТЬ 0, МИНИМУМ(ВТ_2.Начало), ЛОЖЬ ИЗ ВТ_20 КАК ВТ_2 ИМЕЮЩИЕ МИНИМУМ(ВТ_2.Начало) > 0 ОБЪЕДИНИТЬ ВЫБРАТЬ МАКСИМУМ(ВТ_2.Окончание), 24, ЛОЖЬ ИЗ ВТ_20 КАК ВТ_2 ИМЕЮЩИЕ МАКСИМУМ(ВТ_2.Окончание) < 24 ОБЪЕДИНИТЬ ВЫБРАТЬ ВТ_2.Окончание, ВТ_21.Начало, ЛОЖЬ ИЗ ВТ_20 КАК ВТ_2 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_20 КАК ВТ_21 ПО ВТ_2.Окончание < ВТ_21.Начало ЛЕВОЕ СОЕДИНЕНИЕ ВТ_20 КАК ВТ_22 ПО ВТ_2.Окончание < ВТ_22.Начало И (ВТ_22.Начало < ВТ_21.Начало) ГДЕ ВТ_22.Начало ЕСТЬ NULL ; //////////////////////////////////////////////////////////////////////////////// УНИЧТОЖИТЬ ВТ_20 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_1.Начало, ВТ_1.Окончание, ВТ_1.Рабочее КАК Первый, ЛОЖЬ КАК Второй ИЗ ВТ_1 КАК ВТ_1 ЛЕВОЕ СОЕДИНЕНИЕ ВТ_2 КАК ВТ_2 ПО ВТ_1.Начало <= ВТ_2.Начало И ВТ_1.Окончание > ВТ_2.Начало ГДЕ ВТ_2.Начало ЕСТЬ NULL ОБЪЕДИНИТЬ ВЫБРАТЬ ВЫБОР КОГДА ВТ_1.Начало < ВТ_2.Начало ТОГДА ВТ_2.Начало ИНАЧЕ ВТ_1.Начало КОНЕЦ, ВЫБОР КОГДА ВТ_1.Окончание > ВТ_2.Окончание ТОГДА ВТ_2.Окончание ИНАЧЕ ВТ_1.Окончание КОНЕЦ, ВТ_1.Рабочее, ВТ_2.Рабочее ИЗ ВТ_1 КАК ВТ_1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_2 КАК ВТ_2 ПО ВТ_1.Начало <= ВТ_2.Начало И ВТ_1.Окончание > ВТ_2.Начало ОБЪЕДИНИТЬ ВЫБРАТЬ ВТ_2.Начало, ВТ_2.Окончание, ЛОЖЬ, ВТ_2.Рабочее ИЗ ВТ_2 КАК ВТ_2 ЛЕВОЕ СОЕДИНЕНИЕ ВТ_1 КАК ВТ_1 ПО ВТ_2.Начало <= ВТ_1.Начало И ВТ_2.Окончание > ВТ_1.Начало ГДЕ ВТ_1.Начало ЕСТЬ NULL ОБЪЕДИНИТЬ ВЫБРАТЬ ВЫБОР КОГДА ВТ_2.Начало < ВТ_1.Начало ТОГДА ВТ_1.Начало ИНАЧЕ ВТ_2.Начало КОНЕЦ, ВЫБОР КОГДА ВТ_2.Окончание > ВТ_1.Окончание ТОГДА ВТ_1.Окончание ИНАЧЕ ВТ_2.Окончание КОНЕЦ, ВТ_1.Рабочее, ВТ_2.Рабочее ИЗ ВТ_2 КАК ВТ_2 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_1 КАК ВТ_1 ПО ВТ_2.Начало <= ВТ_1.Начало И ВТ_2.Окончание > ВТ_1.Начало </Code> |
|||
21
PCcomCat
09.06.17
✎
11:01
|
В общем, я как упёртая или упоротая, пошла путем вычисления левых и правых интервалов.
Окончательный рабочий код для вышеуказанного примера: ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 8, 0, 0) КАК От, ДАТАВРЕМЯ(1, 1, 1, 12, 0, 0) КАК До, "раб. время" КАК ТипВремени ПОМЕСТИТЬ ИнтервалыДня ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 13, 0, 0), ДАТАВРЕМЯ(1, 1, 1, 17, 0, 0), "раб. время" ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0), ДАТАВРЕМЯ(1, 1, 1, 8, 0, 0), "нераб. время" ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 12, 0, 0), ДАТАВРЕМЯ(1, 1, 1, 13, 0, 0), "нераб. время" ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 17, 0, 0), ДАТАВРЕМЯ(1, 1, 1, 23, 59, 0), "нераб. время" ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 9, 0, 0) КАК От, ДАТАВРЕМЯ(1, 1, 1, 11, 0, 0) КАК До, "1-ая работа" КАК Работа ПОМЕСТИТЬ ИнтервалыРабот ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(1, 1, 1, 12, 0, 0), ДАТАВРЕМЯ(1, 1, 1, 16, 0, 0), "2-я работа" ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВЫБОР КОГДА ИнтервалыДня.От >= ЕСТЬNULL(ИнтервалыРабот.От, ДАТАВРЕМЯ(1, 1, 1)) ТОГДА ИнтервалыДня.От ИНАЧЕ ЕСТЬNULL(ИнтервалыРабот.От, ДАТАВРЕМЯ(1, 1, 1)) КОНЕЦ КАК От, ВЫБОР КОГДА ИнтервалыДня.До <= ЕСТЬNULL(ИнтервалыРабот.До, ДАТАВРЕМЯ(1, 1, 2)) ТОГДА ИнтервалыДня.До ИНАЧЕ ЕСТЬNULL(ИнтервалыРабот.До, ДАТАВРЕМЯ(1, 1, 2)) КОНЕЦ КАК До, ВЫБОР КОГДА ИнтервалыРабот.Работа ЕСТЬ NULL ТОГДА "Без пересечения" ИНАЧЕ "Пересечение" КОНЕЦ КАК ВидИнтервала, ИнтервалыДня.ТипВремени КАК ТипВремени, ИнтервалыРабот.Работа КАК Работа, ИнтервалыДня.От КАК ИнтервалНачало, ИнтервалыДня.До КАК ИнтервалКонец, ИнтервалыРабот.От КАК РаботаНачало, ИнтервалыРабот.До КАК РаботаКонец ИЗ ИнтервалыДня КАК ИнтервалыДня ЛЕВОЕ СОЕДИНЕНИЕ ИнтервалыРабот КАК ИнтервалыРабот ПО (ИнтервалыРабот.От <= ИнтервалыДня.До) И (ИнтервалыРабот.До >= ИнтервалыДня.От) ГДЕ ВЫБОР КОГДА ИнтервалыДня.От >= ЕСТЬNULL(ИнтервалыРабот.От, ДАТАВРЕМЯ(1, 1, 1)) ТОГДА ИнтервалыДня.От ИНАЧЕ ЕСТЬNULL(ИнтервалыРабот.От, ДАТАВРЕМЯ(1, 1, 1)) КОНЕЦ <> ВЫБОР КОГДА ИнтервалыДня.До <= ЕСТЬNULL(ИнтервалыРабот.До, ДАТАВРЕМЯ(1, 1, 2)) ТОГДА ИнтервалыДня.До ИНАЧЕ ЕСТЬNULL(ИнтервалыРабот.До, ДАТАВРЕМЯ(1, 1, 2)) КОНЕЦ ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ВЫБОР КОГДА ИнтервалыДня.От >= ИнтервалыРабот.От ТОГДА ИнтервалыРабот.От ИНАЧЕ ИнтервалыДня.От КОНЕЦ, ВЫБОР КОГДА ИнтервалыДня.От >= ИнтервалыРабот.От ТОГДА ИнтервалыДня.От ИНАЧЕ ИнтервалыРабот.От КОНЕЦ, "Левый", ИнтервалыДня.ТипВремени, "", ИнтервалыДня.От, ИнтервалыДня.До, ИнтервалыРабот.От, ИнтервалыРабот.До ИЗ ИнтервалыДня КАК ИнтервалыДня ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИнтервалыРабот КАК ИнтервалыРабот ПО (ИнтервалыРабот.От < ИнтервалыДня.До) И (ИнтервалыРабот.До >= ИнтервалыДня.От) И (ИнтервалыРабот.От >= ИнтервалыДня.От) ГДЕ ВЫБОР КОГДА ИнтервалыДня.От >= ИнтервалыРабот.От ТОГДА ИнтервалыРабот.От ИНАЧЕ ИнтервалыДня.От КОНЕЦ <> ВЫБОР КОГДА ИнтервалыДня.От >= ИнтервалыРабот.От ТОГДА ИнтервалыДня.От ИНАЧЕ ИнтервалыРабот.От КОНЕЦ ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ВЫБОР КОГДА ИнтервалыДня.До <= ИнтервалыРабот.До ТОГДА ИнтервалыДня.До ИНАЧЕ ИнтервалыРабот.До КОНЕЦ, ВЫБОР КОГДА ИнтервалыДня.До <= ИнтервалыРабот.До ТОГДА ИнтервалыРабот.До ИНАЧЕ ИнтервалыДня.До КОНЕЦ, "Правый", ИнтервалыДня.ТипВремени, "", ИнтервалыДня.От, ИнтервалыДня.До, ИнтервалыРабот.От, ИнтервалыРабот.До ИЗ ИнтервалыДня КАК ИнтервалыДня ВНУТРЕННЕЕ СОЕДИНЕНИЕ ИнтервалыРабот КАК ИнтервалыРабот ПО (ИнтервалыРабот.От < ИнтервалыДня.До) И (ИнтервалыРабот.До >= ИнтервалыДня.От) И (ИнтервалыРабот.До <= ИнтервалыДня.До) ГДЕ ВЫБОР КОГДА ИнтервалыДня.До <= ИнтервалыРабот.До ТОГДА ИнтервалыДня.До ИНАЧЕ ИнтервалыРабот.До КОНЕЦ <> ВЫБОР КОГДА ИнтервалыДня.До <= ИнтервалыРабот.До ТОГДА ИнтервалыРабот.До ИНАЧЕ ИнтервалыДня.До КОНЕЦ УПОРЯДОЧИТЬ ПО От Не исключаю, конечно, косяки. Их уже буду проверять на реальных данных - в бою, так сказать. Еще раз выражаю благодарность Ildarovich ! Лично я не додумалась, например, до этого ЕСТЬNULL(ИнтервалыРабот.До, ДАТАВРЕМЯ(1, 1, 2!)). |
|||
22
eryomin
09.06.17
✎
11:03
|
Никак не могу побороть форматирование:
<CODE> ВЫБРАТЬ 8 КАК Начало, 12 КАК Окончание ПОМЕСТИТЬ ВТ_10 ОБЪЕДИНИТЬ ВЫБРАТЬ 13, 17 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_1.Начало КАК Начало, ВТ_1.Окончание КАК Окончание, ИСТИНА КАК Рабочее ПОМЕСТИТЬ ВТ_1 ИЗ ВТ_10 КАК ВТ_1 ОБЪЕДИНИТЬ ВЫБРАТЬ 0, МИНИМУМ(ВТ_1.Начало), ЛОЖЬ ИЗ ВТ_10 КАК ВТ_1 ИМЕЮЩИЕ МИНИМУМ(ВТ_1.Начало) > 0 ОБЪЕДИНИТЬ ВЫБРАТЬ МАКСИМУМ(ВТ_1.Окончание), 24, ЛОЖЬ ИЗ ВТ_10 КАК ВТ_1 ИМЕЮЩИЕ МАКСИМУМ(ВТ_1.Окончание) < 24 ОБЪЕДИНИТЬ ВЫБРАТЬ ВТ_1.Окончание, ВТ_11.Начало, ЛОЖЬ ИЗ ВТ_10 КАК ВТ_1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_10 КАК ВТ_11 ПО ВТ_1.Окончание < ВТ_11.Начало ЛЕВОЕ СОЕДИНЕНИЕ ВТ_10 КАК ВТ_12 ПО ВТ_1.Окончание < ВТ_12.Начало И (ВТ_12.Начало < ВТ_11.Начало) ГДЕ ВТ_12.Начало ЕСТЬ NULL ; //////////////////////////////////////////////////////////////////////////////// УНИЧТОЖИТЬ ВТ_10 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ 12 КАК Начало, 16 КАК Окончание ПОМЕСТИТЬ ВТ_20 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_2.Начало КАК Начало, ВТ_2.Окончание КАК Окончание, ИСТИНА КАК Рабочее ПОМЕСТИТЬ ВТ_2 ИЗ ВТ_20 КАК ВТ_2 ОБЪЕДИНИТЬ ВЫБРАТЬ 0, МИНИМУМ(ВТ_2.Начало), ЛОЖЬ ИЗ ВТ_20 КАК ВТ_2 ИМЕЮЩИЕ МИНИМУМ(ВТ_2.Начало) > 0 ОБЪЕДИНИТЬ ВЫБРАТЬ МАКСИМУМ(ВТ_2.Окончание), 24, ЛОЖЬ ИЗ ВТ_20 КАК ВТ_2 ИМЕЮЩИЕ МАКСИМУМ(ВТ_2.Окончание) < 24 ОБЪЕДИНИТЬ ВЫБРАТЬ ВТ_2.Окончание, ВТ_21.Начало, ЛОЖЬ ИЗ ВТ_20 КАК ВТ_2 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_20 КАК ВТ_21 ПО ВТ_2.Окончание < ВТ_21.Начало ЛЕВОЕ СОЕДИНЕНИЕ ВТ_20 КАК ВТ_22 ПО ВТ_2.Окончание < ВТ_22.Начало И (ВТ_22.Начало < ВТ_21.Начало) ГДЕ ВТ_22.Начало ЕСТЬ NULL ; //////////////////////////////////////////////////////////////////////////////// УНИЧТОЖИТЬ ВТ_20 ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ВТ_1.Начало, ВТ_1.Окончание, ВТ_1.Рабочее КАК Первый, ЛОЖЬ КАК Второй ИЗ ВТ_1 КАК ВТ_1 ЛЕВОЕ СОЕДИНЕНИЕ ВТ_2 КАК ВТ_2 ПО ВТ_1.Начало <= ВТ_2.Начало И ВТ_1.Окончание > ВТ_2.Начало ГДЕ ВТ_2.Начало ЕСТЬ NULL ОБЪЕДИНИТЬ ВЫБРАТЬ ВЫБОР КОГДА ВТ_1.Начало < ВТ_2.Начало ТОГДА ВТ_2.Начало ИНАЧЕ ВТ_1.Начало КОНЕЦ, ВЫБОР КОГДА ВТ_1.Окончание > ВТ_2.Окончание ТОГДА ВТ_2.Окончание ИНАЧЕ ВТ_1.Окончание КОНЕЦ, ВТ_1.Рабочее, ВТ_2.Рабочее ИЗ ВТ_1 КАК ВТ_1 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_2 КАК ВТ_2 ПО ВТ_1.Начало <= ВТ_2.Начало И ВТ_1.Окончание > ВТ_2.Начало ОБЪЕДИНИТЬ ВЫБРАТЬ ВТ_2.Начало, ВТ_2.Окончание, ЛОЖЬ, ВТ_2.Рабочее ИЗ ВТ_2 КАК ВТ_2 ЛЕВОЕ СОЕДИНЕНИЕ ВТ_1 КАК ВТ_1 ПО ВТ_2.Начало <= ВТ_1.Начало И ВТ_2.Окончание > ВТ_1.Начало ГДЕ ВТ_1.Начало ЕСТЬ NULL ОБЪЕДИНИТЬ ВЫБРАТЬ ВЫБОР КОГДА ВТ_2.Начало < ВТ_1.Начало ТОГДА ВТ_1.Начало ИНАЧЕ ВТ_2.Начало КОНЕЦ, ВЫБОР КОГДА ВТ_2.Окончание > ВТ_1.Окончание ТОГДА ВТ_1.Окончание ИНАЧЕ ВТ_2.Окончание КОНЕЦ, ВТ_1.Рабочее, ВТ_2.Рабочее ИЗ ВТ_2 КАК ВТ_2 ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_1 КАК ВТ_1 ПО ВТ_2.Начало <= ВТ_1.Начало И ВТ_2.Окончание > ВТ_1.Начало </CODE> |
|||
23
PCcomCat
09.06.17
✎
11:25
|
(22) Да, результат тот же, объединений больше)). Только если я добавлю еще интервал работ 9-11, то некоторые отрезки задваиваются.
Тоже спасибо! |
|||
24
Ildarovich
13.06.17
✎
14:37
|
Осталась некоторая неудовлетворенность приведенными решениями этой задачи. Поэтому добавлю полное решение, которое кажется более простым:
ВЫБРАТЬ 8 КАК От, 12 КАК До, "раб. время" КАК ТипВремени
Принцип решения в том, чтобы все моменты времени (все начала, концы интервалов, 0, 24) собрать без повторений в одну таблицу, затем по этой таблице построить все самые мелкие интервалы, а к ним уже присоединять включающие их интервалы работ, рабочего времени и тому подобное. Такой принцип будет работать и для больше чем двух таблиц пересекающихся интервалов.
Проблема этого и всех приведенных запросов в том, что они будут сильно терять производительность при росте количества интервалов (если их станет больше нескольких тысяч). С этим можно справится, применяя прием из статьи http://catalog.mista.ru/public/402534/ для определения интервалов и прием из статьи http://catalog.mista.ru/public/551583/ (или его упрощенную версию) для определения пересечения интервалов. |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |