При разработке бизнес-логики в 1С регулярно возникает задача анализа данных в объекте ТаблицаЗначений. Одной из распространенных задач является сравнение строк между собой по колонкам с временными интервалами, такими как ДатаНачала и ДатаКонца. Рассмотрим подробно, как правильно организовать перебор и проверку строк, какие особенности платформы 1С следует учитывать и какие алгоритмы подходят для решения данной задачи.
Если требуется проанализировать каждую строку таблицы значений и проверить соответствие даты заданному условию или значению, используется стандартный цикл Для Каждого. Проанализируем простой пример кода:
Для Каждого СтрокаТЗ Из ТаблицаЗначений Цикл
Если СтрокаТЗ.ДатаНачала <= ТекущаяДата() Тогда
// Выполняем необходимую обработку строки
СтрокаТЗ.Обработана = Истина;
КонецЕсли;
КонецЦикла;
Этот способ отлично подходит, когда нужно сравнить значение каждой строки с внешним параметром или константой.
Когда требуется сравнить строки одной и той же таблицы друг с другом (например, проверить, не перекрываются ли периоды ДатаНачала и ДатаКонца в разных строках), простая итерация по одному циклу не позволит сопоставить каждую пару строк. В этом случае применяют алгоритм с предварительной сортировкой и двойным циклом по индексам.
Разберем по шагам реализацию данного алгоритма:
Сортировать(). Это позволит упорядочить временные отрезки.0 до Количество() - 2.ИндексВнешнего + 1 до Количество() - 1. Такое построение исключает сравнение строки с самой собой и повторные проверки уже обработанных пар.Посмотрим на пример реализации данного подхода в коде:
// Шаг 1. Сортировка таблицы по дате начала
ТаблицаЗначений.Сортировать("ДатаНачала Возр");
ВсегоСтрок = ТаблицаЗначений.Количество();
// Шаг 2 и 3. Перебор пар строк по индексам
Для Индекс1 = 0 По ВсегоСтрок - 2 Цикл
Строка1 = ТаблицаЗначений[Индекс1];
Для Индекс2 = Индекс1 + 1 По ВсегоСтрок - 1 Цикл
Строка2 = ТаблицаЗначений[Индекс2];
// Учитываем возможные пустые даты окончания (бесконечный период)
ДатаКонца1 = ?(ЗначениеЗаполнено(Строка1.ДатаКонца), Строка1.ДатаКонца, Дата('39991231'));
ДатаКонца2 = ?(ЗначениеЗаполнено(Строка2.ДатаКонца), Строка2.ДатаКонца, Дата('39991231'));
// Шаг 4. Проверка пересечения интервалов
Если (Строка1.ДатаНачала <= ДатаКонца2) И (ДатаКонца1 >= Строка2.ДатаНачала) Тогда
// Обнаружено пересечение периодов
Сообщить("Период в строке " + Индекс1 + " пересекается с периодом в строке " + Индекс2);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Даже если исходная ТаблицаЗначений сформирована программно, а не запросом к базе данных, для сложного анализа удобнее передать ее в объект Запрос. В запросе можно выполнить внутреннее или левое соединение таблицы с самой собой по условиям наложения интервалов.
Рассмотрим пример кода для обработки таблицы значений через запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТЗ1.НомерСтроки КАК Номер1,
| ТЗ2.НомерСтроки КАК Номер2
|ИЗ
| &ТЗ КАК ТЗ1
| ВНУТРЕННЕЕ СОЕДИНЕНИЕ &ТЗ КАК ТЗ2
| ПО ТЗ1.НомерСтроки <> ТЗ2.НомерСтроки
| И (ТЗ1.ДатаНачала <= ТЗ2.ДатаКонца ИЛИ ТЗ2.ДатаКонца = ДАТАВРЕМЯ(1, 1, 1))
| И (ТЗ1.ДатаКонца >= ТЗ2.ДатаНачала ИЛИ ТЗ1.ДатаКонца = ДАТАВРЕМЯ(1, 1, 1))";
Запрос.УстановитьПараметр("ТЗ", ТаблицаЗначений);
РезультатЗапроса = Запрос.Выполнить();
Выясним ключевые нюансы, о которых необходимо помнить при работе с объектом ТаблицаЗначений:
ТаблицаЗначений доступен на сервере, в толстом клиенте и во внешнем соединении. На тонком клиенте и веб-клиенте вместо него используется ДанныеФормыКоллекция.ТаблицаЗначений в запрос в качестве параметра для каждой колонки таблицы должно быть обязательно задано строгое ОписаниеТипов. Если колонки созданы без явного указания типов (например, типа Дата), платформа выдаст ошибку при выполнении запроса.НайтиСтроки(): Встроенный метод НайтиСтроки() выполняет поиск исключительно по точечному совпадению (равенству) значений. Проверить вхождение даты в диапазон или пересечение интервалов с помощью этого метода нельзя.'00010101'. В логике интервалов незаполненная ДатаКонца обычно трактуется как неограниченный период. Если не обрабатывать пустое значение отдельно, система сочтет пустую дату наименьшим возможным значением, что приведет к ошибкам в логике.