ВЫБРАТЬ
1 КАК Дата
ПОМЕСТИТЬ Даты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
3
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
5
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
6
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата
ПОМЕСТИТЬ ПервыеДатыИнтервалов
ИЗ
Даты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ Даты КАК ДатыДо
ПО (ДатыДо.Дата = Даты.Дата - 1)
ГДЕ
ДатыДо.Дата ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата
ПОМЕСТИТЬ ПоследниеДатыИнтервалов
ИЗ
Даты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ Даты КАК ДатыПосле
ПО (Даты.Дата + 1 = ДатыПосле.Дата)
ГДЕ
ДатыПосле.Дата ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПервыеДатыИнтервалов.Дата КАК ДатаНач,
МИНИМУМ(ПоследниеДатыИнтервалов.Дата) КАК ДатаКон
ИЗ
ПервыеДатыИнтервалов КАК ПервыеДатыИнтервалов
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПоследниеДатыИнтервалов КАК ПоследниеДатыИнтервалов
ПО ПервыеДатыИнтервалов.Дата <= ПоследниеДатыИнтервалов.Дата
СГРУППИРОВАТЬ ПО
ПервыеДатыИнтервалов.Дата
Показать
Не стал измерения приводить, смысл от этого не меняется
ВЫБРАТЬ
РСведений.Измерение1,
РСведений.Дата КАК Дата
ПОМЕСТИТЬ Ч
ИЗ
РегистрСведений.РСведений КАК РСведений
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Ч.Измерение1,
Ч.Дата КАК Дата,
МИНИМУМ(Ч1.Дата) КАК Дата1
ИЗ
Ч КАК Ч
ЛЕВОЕ СОЕДИНЕНИЕ Ч КАК Ч1
ПО Ч.Измерение1 = Ч1.Измерение1
И Ч.Дата < Ч1.Дата
СГРУППИРОВАТЬ ПО
Ч.Дата,
Ч.Измерение1
УПОРЯДОЧИТЬ ПО
Дата
ВЫБРАТЬ Т1.Период,Т2.Период
ПОМЕСТИТЬ КОНЦЫ
ИЗ РегистрСведений.Тест как Т1
ЛЕВОЕ СОЕДИНЕНИЕ
РегистрСведений.Тест как Т2
ПО Т2.Период=ДОБАВИТЬКДАТЕ(Т1.Период,День,1)
ГДЕ Т2.Период ЕСТЬ NULL;
ВЫБРАТЬ
Т3.Период как ТКонец,
ЕСТЬNULL(МАКСИМУМ(Т4.Период),ДАТАВРЕМЯ(1,1,1)) как ПКонец
ПОМЕСТИТЬ КОНЦЫ2
ИЗ КОНЦЫ как Т3
ЛЕВОЕ СОЕДИНЕНИЕ
КОНЦЫ как Т4
ПО Т4.Период<Т3.Период
СГРУППИРОВАТЬ ПО Т3.Период;
ВЫБРАТЬ
МИНИМУМ(Т6.Период) как днач,
Т5.ТКонец как дкон
ИЗ КОНЦЫ2 как Т5
СОЕДИНЕНИЕ
РегистрСведений.Тест как Т6
ПО Т6.Период<=Т5.ТКонец
И Т6.Период>Т5.ПКонец
СГРУППИРОВАТЬ ПО Т5.Тконец
УПОРЯДОЧИТЬ ПО 1
Задача не простая.
Условие соединения это найти интервалы в которых условие даты n=n+1
P1 02.06.2014 04.06.2014
P1 10.06.2014 12.06.2014
P1 17.06.2014 19.06.2014
Для того чтобы решить задачу нужно понять какое условие, не на приведенные конкретные данные + "должно получиться так", а универсальное условие для любого набора данных
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 2) КАК Дата
ПОМЕСТИТЬ ТаблицаРегистра
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 3)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 4)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 10)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 11)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 12)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 17)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 18)
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 19)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ТаблицаРегистра.Дата КАК ДатаНачала,
ТаблицаРегистраДляСоединения.Дата КАК ДатаОкончания
ИЗ
ТаблицаРегистра КАК ТаблицаРегистра
ЛЕВОЕ СОЕДИНЕНИЕ ТаблицаРегистра КАК ТаблицаРегистраДляСоединения
ПО (ДОБАВИТЬКДАТЕ(ТаблицаРегистра.Дата, ДЕНЬ, 2) = ТаблицаРегистраДляСоединения.Дата)
ГДЕ
НЕ ТаблицаРегистраДляСоединения.Дата ЕСТЬ NULL
ВЫБРАТЬ
1 КАК Дата
ПОМЕСТИТЬ Даты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
3
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
5
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
6
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата
ПОМЕСТИТЬ ПервыеДатыИнтервалов
ИЗ
Даты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ Даты КАК ДатыДо
ПО (ДатыДо.Дата = Даты.Дата - 1)
ГДЕ
ДатыДо.Дата ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата
ПОМЕСТИТЬ ПоследниеДатыИнтервалов
ИЗ
Даты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ Даты КАК ДатыПосле
ПО (Даты.Дата + 1 = ДатыПосле.Дата)
ГДЕ
ДатыПосле.Дата ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПервыеДатыИнтервалов.Дата КАК ДатаНач,
МИНИМУМ(ПоследниеДатыИнтервалов.Дата) КАК ДатаКон
ИЗ
ПервыеДатыИнтервалов КАК ПервыеДатыИнтервалов
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПоследниеДатыИнтервалов КАК ПоследниеДатыИнтервалов
ПО ПервыеДатыИнтервалов.Дата <= ПоследниеДатыИнтервалов.Дата
СГРУППИРОВАТЬ ПО
ПервыеДатыИнтервалов.Дата
Показать
Не стал измерения приводить, смысл от этого не меняется
Правильное решение! Спасибо!
Всем большое спасибо Если есть оптимальные методы то пишите!
Вот окончательный текст запроса
ВЫБРАТЬ
Вз.Дата,
Вз.Измерение
ПОМЕСТИТЬ ВТДаты
ИЗ
(ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 1, 0, 0, 0) КАК Дата,
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10)) КАК Измерение
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 2, 0, 0, 0),
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10))
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 5, 0, 0, 0),
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10))
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 6, 0, 0, 0),
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10))
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 7, 0, 0, 0),
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10))
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 8, 0, 0, 0),
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10))
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ДАТАВРЕМЯ(2014, 6, 22, 0, 0, 0),
ВЫРАЗИТЬ("Иванов" КАК СТРОКА(10))) КАК Вз
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата
ПОМЕСТИТЬ ПервыеДатыИнтервалов
ИЗ
ВТДаты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ ВТДаты КАК ДатыДо
ПО (ДатыДо.Дата = ДОБАВИТЬКДАТЕ(Даты.Дата, ДЕНЬ, -1))
ГДЕ
ДатыДо.Дата ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата
ПОМЕСТИТЬ ПоследниеДатыИнтервалов
ИЗ
ВТДаты КАК Даты
ЛЕВОЕ СОЕДИНЕНИЕ ВТДаты КАК ДатыПосле
ПО (ДатыПосле.Дата = ДОБАВИТЬКДАТЕ(Даты.Дата, ДЕНЬ, 1))
ГДЕ
ДатыПосле.Дата ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПервыеДатыИнтервалов.Дата КАК ДатаНач,
МИНИМУМ(ПоследниеДатыИнтервалов.Дата) КАК ДатаКон
ИЗ
ПервыеДатыИнтервалов КАК ПервыеДатыИнтервалов
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ПоследниеДатыИнтервалов КАК ПоследниеДатыИнтервалов
ПО ПервыеДатыИнтервалов.Дата <= ПоследниеДатыИнтервалов.Дата
Пишу ещё раз условие есть регистр сведений периодичностью месяц назывееться больничные, там 2 измерения сотрудник и дата болезни.
Пользователь проставляет даты больничных пример
Иванов болел 1.06 , 2.06, ,11.06,12.06, 29.06 .
Нужно найти интервалы болезни
ДЛЯ Иванова:
(20) igormiro, скопируй сюда данные твоего регистра, или проще всего приложи скрин. а то на самом деле не совсем понятно, какие данные имеются и что все-таки хочешь получить.
непонятно как из "1.06 , 2.06, ,11.06,12.06, 29.06" получается:
1.06 - 2.06,
10.06-12.06
29.06-29.06
ВЫБРАТЬ
"P1" КАК Измерение1,
ДАТАВРЕМЯ(2014, 6, 2) КАК Дата
ПОМЕСТИТЬ ВТДаты
;
ВЫБРАТЬ
ЕСТЬNULL(ВТДаты.Измерение1, ВТДаты1.Измерение1) КАК Измерение1,
ВТДаты.Дата КАК Дата,
ВТДаты1.Дата КАК СледующаяДата
ПОМЕСТИТЬ ВТТаблица
ИЗ
ВТДаты КАК ВТДаты
ПОЛНОЕ СОЕДИНЕНИЕ ВТДаты КАК ВТДаты1
ПО ВТДаты.Измерение1 = ВТДаты1.Измерение1
И (ДОБАВИТЬКДАТЕ(ВТДаты.Дата, ДЕНЬ, 1) = ВТДаты1.Дата)
ГДЕ
(ВТДаты.Дата ЕСТЬ NULL ИЛИ ВТДаты1.Дата ЕСТЬ NULL)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
ВТДаты.Измерение1,
МАКСИМУМ(ВТДатыС.СледующаяДата) КАК ДатаС,
МИНИМУМ(ВТДатыПо.Дата) КАК ДатаПо
ИЗ
ВТДаты КАК ВТДаты
ЛЕВОЕ СОЕДИНЕНИЕ ВТТаблица КАК ВТДатыС
ПО ВТДаты.Измерение1 = ВТДатыС.Измерение1
И ВТДаты.Дата >= ВТДатыС.СледующаяДата
ЛЕВОЕ СОЕДИНЕНИЕ ВТТаблица КАК ВТДатыПо
ПО ВТДаты.Измерение1 = ВТДатыПо.Измерение1
И ВТДаты.Дата <= ВТДатыПо.Дата
СГРУППИРОВАТЬ ПО
ВТДаты.Измерение1,
ВТДаты.Дата
ВЫБРАТЬ
ЕСТЬNULL(ВТДаты.Измерение1, ВТДаты1.Измерение1) КАК Измерение1,
ВТДаты.Дата КАК Дата,
ВТДаты1.Дата КАК СледующаяДата
ПОМЕСТИТЬ ВТТаблица
ИЗ
ВТДаты КАК ВТДаты
ПОЛНОЕ СОЕДИНЕНИЕ ВТДаты КАК ВТДаты1
ПО ВТДаты.Измерение1 = ВТДаты1.Измерение1
И (ДОБАВИТЬКДАТЕ(ВТДаты.Дата, ДЕНЬ, 1) = ВТДаты1.Дата)
ГДЕ
(ВТДаты.Дата ЕСТЬ NULL
ИЛИ ВТДаты1.Дата ЕСТЬ NULL )
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТДатыС.Измерение1,
ВТДатыС.СледующаяДата КАК ДатаС,
МИНИМУМ(ВТДатыПо.Дата) КАК Дата
ИЗ
ВТТаблица КАК ВТДатыС
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТТаблица КАК ВТДатыПо
ПО ВТДатыС.Измерение1 = ВТДатыПо.Измерение1
И ВТДатыС.СледующаяДата <= ВТДатыПо.Дата
СГРУППИРОВАТЬ ПО
ВТДатыС.Измерение1,
ВТДатыС.СледующаяДата
ВЫБРАТЬ
Даты.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДатыДо.Дата) КАК Номер
ПОМЕСТИТЬ НомераДат
ИЗ
ВТДаты КАК Даты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТДаты КАК ДатыДо
ПО (ДатыДо.Дата <= Даты.Дата)
СГРУППИРОВАТЬ ПО
Даты.Дата
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(НомераДат.Дата) КАК ДатаНач,
МАКСИМУМ(НомераДат.Дата) КАК ДатаКон
ИЗ
НомераДат КАК НомераДат
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(НомераДат.Дата, ДЕНЬ, -НомераДат.Номер)
(34) miniogn, задача связывания начал отрезков с их концами (решаемая в вашем подходе в последнем запросе) - это примерно такая же по вычислительной сложности задача, только она будет зависеть от квадрата числа отрезков, а при подсчете количества дат - от квадрата количества дат.
Также кажется, что для соединения по условию
(ДатыДо.Дата = ДОБАВИТЬКДАТЕ(Даты.Дата, ДЕНЬ, -1))
придется для каждой даты просканировать все другие даты. Это тоже задача, имеющая квадратичную трудоемкость. Правда, последнюю трудность можно преодолеть, используя вместо соединения группировку.
А вообще я знаю как решить эту задачу за линейное время, используя метод типа "баттерфляй", но здесь речь не шла о высочайшей скорости и супербольших объемах данных, поэтому я и предложил суперкомпактный метод.
ВЫБРАТЬ
ТаблицаДат.Дата КАК Дата,
ТаблицаДат.ВидДеятельности КАК ВидДеятельности
ПОМЕСТИТЬ ВТДаты
ИЗ
&ТаблицаДат КАК ТаблицаДат
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата КАК Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ ДатыДо.Дата) КАК Номер,
Даты.ВидДеятельности КАК ВидДеятельности
ПОМЕСТИТЬ НомераДат
ИЗ
ВТДаты КАК Даты
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТДаты КАК ДатыДо
ПО (ДатыДо.Дата <= Даты.Дата)
И Даты.ВидДеятельности = ДатыДо.ВидДеятельности
СГРУППИРОВАТЬ ПО
Даты.Дата,
Даты.ВидДеятельности
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(НомераДат.Дата) КАК ДатаНач,
МАКСИМУМ(НомераДат.Дата) КАК ДатаКон,
НомераДат.ВидДеятельности КАК ВидДеятельности
ИЗ
НомераДат КАК НомераДат
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(НомераДат.Дата, ДЕНЬ, -НомераДат.Номер),
НомераДат.ВидДеятельности
Показать
Теперь решал такую же задачу, только кроме интервала дат, нужно было еще добавить аналитику.
(33) решал похожую задачу. Но там был период в виде начала и конца.
Никак не мог составить условие.
В итоге понял в чем суть и получилось вот такое:
ВЫБРАТЬ
НахождениеВГеозоне.Клиент КАК Клиент,
НахождениеВГеозоне.НачалоПериода КАК НачалоПериода,
НахождениеВГеозоне.КонецПериода КАК КонецПериода,
НахождениеВГеозоне.Геозона КАК Геозона
ПОМЕСТИТЬ Дано
ИЗ
РегистрСведений.НахождениеВГеозоне КАК НахождениеВГеозоне
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Дано.Клиент КАК Клиент,
Дано.НачалоПериода КАК НачалоПериода,
Дано.КонецПериода КАК КонецПериода,
Дано.Геозона КАК Геозона,
СУММА(РАЗНОСТЬДАТ(ДатыДо.НачалоПериода, ДатыДо.КонецПериода, СЕКУНДА)) КАК Интеграл
ПОМЕСТИТЬ ДаноПлюс
ИЗ
Дано КАК Дано
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Дано КАК ДатыДо
ПО (ДатыДо.НачалоПериода <= Дано.НачалоПериода)
И (ДатыДо.Клиент = Дано.Клиент)
И (ДатыДо.Геозона = Дано.Геозона)
СГРУППИРОВАТЬ ПО
Дано.НачалоПериода,
Дано.КонецПериода,
Дано.Клиент,
Дано.Геозона
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(Дано.НачалоПериода) КАК НачалоПериода,
МАКСИМУМ(Дано.КонецПериода) КАК КонецПериода,
Дано.Клиент КАК Клиент,
Дано.Геозона КАК Геозона
ИЗ
ДаноПлюс КАК Дано
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(Дано.КонецПериода, СЕКУНДА, -Дано.Интеграл),
Дано.Клиент,
Дано.Геозона
Показать
Важный момент в определении интервалов "ДатыДо.НачалоПериода <= Дано.НачалоПериода" и "ДОБАВИТЬКДАТЕ(Дано.КонецПериода, СЕКУНДА, -Дано.Интеграл)" в таком ключе интервалы становятся как нужно!
Если период полностью лежит внутри другого периода, то на выходе они двумя отдельными периодами получаются :(
Так что не совсем работает данный метод :(
Пример входных данных для воспроизведения:
ВЫБРАТЬ
"Клиент1" КАК Клиент,
ДАТАВРЕМЯ(2020,01,01,10,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,01,10,15,0,0) КАК КонецПериода,
"Гео1" КАК Геозона
ПОМЕСТИТЬ Дано
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
ДАТАВРЕМЯ(2020,01,01,12,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,01,05,00,0,0) КАК КонецПериода,
"Гео1" КАК Геозона
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
ДАТАВРЕМЯ(2020,02,01,10,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,02,03,10,0,0) КАК КонецПериода,
"Гео1" КАК Геозона
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
ДАТАВРЕМЯ(2020,02,03,10,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,02,14,18,0,0) КАК КонецПериода,
"Гео1" КАК Геозона
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
ДАТАВРЕМЯ(2020,02,04,11,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,02,04,20,0,0) КАК КонецПериода,
"Гео1" КАК Геозона
;
Показать
Должно получиться два периода:
01.01.2020 10:00 - 10.01.2020 15:00
01.02.2020 10:00 - 14.02.2020 18:00
А оно, кроме этих двух периодов, еще два полностью поглощенных периода выводит:
01.01.2020 12:00 - 05.01.2020 00:00
04.02 2020 11:00 - 04.02.2020 20:00
Дополнил Ваше решение, чтобы из результирующей таблицы убирались периоды, которые полностью поглощены другими периодами.
ВЫБРАТЬ
"Клиент1" КАК Клиент,
"Гео1" КАК Геозона,
ДАТАВРЕМЯ(2020,01,01,10,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,01,10,15,0,0) КАК КонецПериода
ПОМЕСТИТЬ Дано
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
"Гео1" КАК Геозона,
ДАТАВРЕМЯ(2020,01,01,12,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,01,05,00,0,0) КАК КонецПериода
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
"Гео1" КАК Геозона,
ДАТАВРЕМЯ(2020,02,01,10,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,02,03,10,0,0) КАК КонецПериода
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
"Гео1" КАК Геозона,
ДАТАВРЕМЯ(2020,02,03,10,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,02,14,18,0,0) КАК КонецПериода
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
"Клиент1" КАК Клиент,
"Гео1" КАК Геозона,
ДАТАВРЕМЯ(2020,02,04,11,0,0) КАК НачалоПериода,
ДАТАВРЕМЯ(2020,02,04,20,0,0) КАК КонецПериода
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Дано.Клиент КАК Клиент,
Дано.НачалоПериода КАК НачалоПериода,
Дано.КонецПериода КАК КонецПериода,
Дано.Геозона КАК Геозона,
СУММА(РАЗНОСТЬДАТ(ДатыДо.НачалоПериода, ДатыДо.КонецПериода, СЕКУНДА)) КАК Интеграл
ПОМЕСТИТЬ ДаноПлюс
ИЗ
Дано КАК Дано
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Дано КАК ДатыДо
ПО (ДатыДо.НачалоПериода <= Дано.НачалоПериода)
И (ДатыДо.Клиент = Дано.Клиент)
И (ДатыДо.Геозона = Дано.Геозона)
СГРУППИРОВАТЬ ПО
Дано.НачалоПериода,
Дано.КонецПериода,
Дано.Клиент,
Дано.Геозона
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МИНИМУМ(Дано.НачалоПериода) КАК НачалоПериода,
МАКСИМУМ(Дано.КонецПериода) КАК КонецПериода,
Дано.Клиент КАК Клиент,
Дано.Геозона КАК Геозона
ПОМЕСТИТЬ вт_РезультатСПоглощенными
ИЗ
ДаноПлюс КАК Дано
СГРУППИРОВАТЬ ПО
ДОБАВИТЬКДАТЕ(Дано.КонецПериода, СЕКУНДА, -Дано.Интеграл),
Дано.Клиент,
Дано.Геозона
;
///////////////////////////////////////////////
// вт_Поглощенные
ВЫБРАТЬ
вт_РезультатСПоглощенными.Клиент КАК Клиент,
вт_РезультатСПоглощенными.Геозона КАК Геозона,
вт_РезультатСПоглощенными.НачалоПериода КАК НачалоПериода,
вт_РезультатСПоглощенными.КонецПериода КАК КонецПериода
ПОМЕСТИТЬ вт_Поглощенные
ИЗ вт_РезультатСПоглощенными КАК вт_РезультатСПоглощенными
ВНУТРЕННЕЕ СОЕДИНЕНИЕ вт_РезультатСПоглощенными КАК Поглотители
ПО вт_РезультатСПоглощенными.Клиент = Поглотители.Клиент
И вт_РезультатСПоглощенными.Геозона = Поглотители.Геозона
И вт_РезультатСПоглощенными.НачалоПериода >= Поглотители.НачалоПериода
И вт_РезультатСПоглощенными.КонецПериода <= Поглотители.КонецПериода
И вт_РезультатСПоглощенными.НачалоПериода <> Поглотители.НачалоПериода
И вт_РезультатСПоглощенными.КонецПериода <> Поглотители.КонецПериода
;
///////////////////////////////////////////////
// Запрос-результат
ВЫБРАТЬ
вт_РезультатСПоглощенными.Клиент КАК Клиент,
вт_РезультатСПоглощенными.Геозона КАК Геозона,
вт_РезультатСПоглощенными.НачалоПериода КАК НачалоПериода,
вт_РезультатСПоглощенными.КонецПериода КАК КонецПериода
ИЗ вт_РезультатСПоглощенными КАК вт_РезультатСПоглощенными
ЛЕВОЕ СОЕДИНЕНИЕ вт_Поглощенные КАК вт_Поглощенные
ПО вт_РезультатСПоглощенными.Клиент = вт_Поглощенные.Клиент
И вт_РезультатСПоглощенными.Геозона = вт_Поглощенные.Геозона
И вт_РезультатСПоглощенными.НачалоПериода = вт_Поглощенные.НачалоПериода
И вт_РезультатСПоглощенными.КонецПериода = вт_Поглощенные.КонецПериода
ГДЕ
вт_Поглощенные.Клиент ЕСТЬ NULL
;
Не. Такое решение тоже не совсем работает.
Если есть период, который пересекает два других периода, соприкасающихся между собой, то запрос не видит поглощение такого периода "объединением соприкасающихся периодов".
Например периоды:
1 - 3 февраля
2 - 4 февраля
3 - 10 февраля
А также, не видит возможность объединить периоды в более сложной ситуации, когда есть три периода, попарно пересекающихся, то запрос не объединяет их в один:
1 - 3 февраля
2 - 5 февраля
4 - 10 февраля
В-общем, правильное решение задачи такое.
Изначальную таблицу периодов помещаем в Дано (см. примеры в предыдущих сообщениях).
А затем в цикле гоняем запросы, пока в последнем запросе количество строк уменьшаться не перестанет (значит объединили все, что можно было объединить).
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Дано.Клиент КАК Клиент,
Дано.Геозона КАК Геозона,
Дано.НачалоПериода КАК НачалоПериода,
Дано.КонецПериода КАК КонецПериода,
СУММА(
РАЗНОСТЬДАТ (
ДатыДо.НачалоПериода,
ВЫБОР
КОГДА ДатыДо.КонецПериода <= Дано.НачалоПериода
ИЛИ (ДатыДо.НачалоПериода = Дано.НачалоПериода И ДатыДо.КонецПериода = Дано.КонецПериода)
ТОГДА
ДатыДо.КонецПериода
ИНАЧЕ
Дано.НачалоПериода
КОНЕЦ,
СЕКУНДА
)
) КАК Интеграл
ПОМЕСТИТЬ ДаноПлюс
ИЗ
Дано КАК Дано
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Дано КАК ДатыДо
ПО (ДатыДо.НачалоПериода <= Дано.НачалоПериода)
И (ДатыДо.Клиент = Дано.Клиент)
И (ДатыДо.Геозона = Дано.Геозона)
СГРУППИРОВАТЬ ПО
Дано.НачалоПериода,
Дано.КонецПериода,
Дано.Клиент,
Дано.Геозона
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ Дано
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Дано.Клиент КАК Клиент,
Дано.Геозона КАК Геозона,
МИНИМУМ(Дано.НачалоПериода) КАК НачалоПериода,
МАКСИМУМ(Дано.КонецПериода) КАК КонецПериода
ПОМЕСТИТЬ Дано
ИЗ
ДаноПлюс КАК Дано
СГРУППИРОВАТЬ ПО
Дано.Клиент,
Дано.Геозона,
ДОБАВИТЬКДАТЕ(Дано.КонецПериода, СЕКУНДА, -Дано.Интеграл)
;
Показать
Обратите внимание на ВЫБОР в первом запросе. Он позволяет объединять пересекающиеся (а не соприкасающиеся) периоды. В том числе и поглощенные периоды убирает.