|
алгоритм поиска пересечений | ☑ | ||
---|---|---|---|---|
0
Oz11
13.03.12
✎
13:36
|
не могу придумать как принцип работы алгоритма поиска пересечения. задача такова: в регистре накопления есть данные (нам важен только период). например, занято с 01.01 - 06.01 и с 09.01 - 14.01. запрашивается период с 5.01 - 10.01. вопрос, как отследить пересечение и выдать пользователю результат. помогите, голова что-то вообще не варит.
|
|||
1
DrShad
13.03.12
✎
13:39
|
а задачу написать русским языком?
|
|||
2
mzelensky
13.03.12
✎
13:41
|
(0) все зависит от того, как ты хранишь (представляшь) эти данные "01.01 - 06.01 и с 09.01 - 14.01"
|
|||
3
Oz11
13.03.12
✎
13:43
|
(1) в регистре накопления хранятся данные об плановом отпуске сотрудника в виде:
период - сотрудник - измерение количестводней - ресурс, например в документе запись о том что сотрудник с 01.01 по 09.01 планирует отпуск, в регистр пойдет 9 записей. 1.период - 01.01 сотрудник - сотрудник количсетводней (1 или 0 в зависимости рабочий день или нет) ...... 9.период - 09.01 сотрудник - сотрудник количсетводней (1 или 0 в зависимости рабочий день или нет) в другом доке запись на отпуск по тому же сотруднику с 7.01 - 10.01 нужно понять что запись пересекается с уже имеющимися в регистре и выдать сообщение |
|||
4
mzelensky
13.03.12
✎
13:47
|
(3) а разве это не в регистрах сведений делается?!
|
|||
5
DrShad
13.03.12
✎
13:47
|
(4) +100501
|
|||
6
Kreont
13.03.12
✎
13:59
|
Задача о сложении/вычитании множеств :)
Сначала через сложение добавляются все "занятые" периоды что б получить одно "огромное" множество "занятых дней", потом через вычитание определяется факт (не)вхождения в первое множество. |
|||
7
Kashemir
13.03.12
✎
14:06
|
(0) При такой постановке вроде все банально - получаешь все используемые интервалы и проверяешь пересечение с каждым интервалом в отдельности.
|
|||
8
vmv
13.03.12
✎
14:08
|
//
// Метод заключается в использовании декартова произведения, особенностью которого является то, что мощность // результата (количество строк) равно произведению мощностей участвующих в декартовом произведении таблиц. // // Результат запроса можно использовать или выгружать в таблицы значений в качестве источника для менеджеров временных // таблиц, выгружать в массивы в качестве параметра в запросах и отборах или использовать сам результат как вложенный запрос // // Естественно, не рекомендуется задавать интервал в тысячи лет, поэтому перед выполнением запроса // сделаем ограничение всего на 50 лет.:) // // Тестирование на формирование интервала в годах и десятках годов // запросом этого метода и созданием аналогичной выборки, например, в массив перебором - однозначно показывает, // что запросный метод производительнее на порядки. // Функция ПолучитьДатыДнейВПериодеКакРезультатЗапроса(ДатаНачала, ДатаОкончания) Экспорт Если ДатаНачала < Дата(2000,1,1) Тогда ДатаНачалаВЗапросе = Дата(2000,1,1); Иначе ДатаНачалаВЗапросе = ДатаНачала; КонецЕсли; Если ДатаОкончания > Дата(2050,1,1) Тогда ДатаОкончанияВЗапросе = Дата(2050,1,1); Иначе ДатаОкончанияВЗапросе = ДатаОкончания; КонецЕсли; ЗапросТекст = "ВЫБРАТЬ | ДОБАВИТЬКДАТЕ(&ДатаНачала, ДЕНЬ, aa.a * 1000 + bb.b * 100 + cc.c * 10 + dd.d) КАК ДатаДня |ИЗ | (ВЫБРАТЬ | 0 КАК a | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 1 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 2 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 3 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 4 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 5 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 6 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 7 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 8 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 9) КАК aa | ПОЛНОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ | 0 КАК b | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 1 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 2 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 3 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 4 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 5 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 6 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 7 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 8 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 9) КАК bb | ПО (ИСТИНА) | ПОЛНОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ | 0 КАК c | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 1 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 2 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 3 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 4 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 5 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 6 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 7 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 8 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 9) КАК cc | ПО (ИСТИНА) | ПОЛНОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ | 0 КАК d | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 1 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 2 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 3 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 4 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 5 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 6 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 7 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 8 | | ОБЪЕДИНИТЬ | | ВЫБРАТЬ | 9) КАК dd | ПО (ИСТИНА) |ГДЕ | aa.a * 1000 + bb.b * 100 + cc.c * 10 + dd.d <= РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ДЕНЬ)"; // Инициализируем переменную запроса, параметры запроса и установим текст запроса Запрос = Новый Запрос; Запрос.УстановитьПараметр("ДатаНачала" , ДатаНачалаВЗапросе); Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончанияВЗапросе); Запрос.Текст = ЗапросТекст; // Собственно выполнение запроса и возврат результата его выполнения Возврат Запрос.Выполнить(); КонецФункции Получаешь результаты запроса для указанных интервалов и делаешь их объединения через МВТ для поиска дырок, аналогичный метод есть и для поиска дырок в числах Можешь поискать дырки для интервалов в сотни лет, попробуй в тысячи, я тестил на тысячелетиях) |
|||
9
Kashemir
13.03.12
✎
14:24
|
ВЫБРАТЬ
ДАТАВРЕМЯ(2012, 1, 1) КАК НачалоИнтервала, ДАТАВРЕМЯ(2012, 1, 6) КАК КонецИнтервала ПОМЕСТИТЬ ТЗЗанятыхИнтервалов ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ДАТАВРЕМЯ(2012, 1, 9), ДАТАВРЕМЯ(2012, 1, 14) ; //////////////////////////////////////////////////////////////////////////////// ВЫБРАТЬ ТЗЗанятыхИнтервалов.НачалоИнтервала, ТЗЗанятыхИнтервалов.КонецИнтервала ИЗ ТЗЗанятыхИнтервалов КАК ТЗЗанятыхИнтервалов ГДЕ (НЕ(ТЗЗанятыхИнтервалов.КонецИнтервала < &ДатаНач ИЛИ ТЗЗанятыхИнтервалов.НачалоИнтервала > &ДатаКон)) |
|||
10
Oz11
13.03.12
✎
14:26
|
всем спасибо огромное за поучения. все оказалось гораздо проще чем я думал. нужно было просто выбрать все записи за проверяемый период и сгруппировать по ресурсу, если число больше 0 - то пересечение есть. правда этот метод не дает самих пересечений (дат), так что возможно еще вернусь к вашим подсказкам. еще раз спасибо.
|
|||
11
МихаилМ
13.03.12
✎
14:46
|
ВЫБРАТЬ *
из ГДЕ (ЗанятоС МЕЖДУ &НачалоИскомогоПериода и &КонецИскомогоПериода ) ИЛИ (ЗанятоПО МЕЖДУ &НачалоИскомогоПериода и &КонецИскомогоПериода ) !!! в рег накопления Вы НЕ сможете хранить ХОТЬ СКОЛЬКО нибуть эффективный индекс по интервалу. значит будет фул скан. и при количествах записей больше 100 000 жуткие тормоза. поэтому рег сведений подходит лучше. далее чтобы повысить селективность добовляют в начало уточняющие поля (актуальность ) либо 1 запись заменяют кортежем сразбивкой на интервалы (месяц - 5 мин) (подальше положешь - поближе возьмёшь) в последних версиях ms sql и postgre sql появились для этих целей пространственные индексы. |
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |