В процессе разработки отчетов в системе компоновки данных (СКД), особенно для отраслевых решений вроде «Управление автотранспортом» (УАТ), часто возникает задача поиска ошибочных или избыточных данных. Одной из таких задач является выявление «дублей» — ситуаций, когда на одно и то же ТранспортноеСредство или на одного Пассажира выписано несколько документов (например, уатПутевойЛист) в течение одного дня. Рассмотрим подробно, как реализовать такой механизм с использованием параметров-флагов («галочек») непосредственно в запросе СКД.
Представим ситуацию: у нас есть стандартный запрос, выбирающий данные из таблицы документов. Нам необходимо добавить в настройки отчета два параметра типа Булево: ТолькоДублиАвтомобилей и ТолькоДублиПассажиров. При установке этих флагов отчет должен выводить не все записи, а только те, которые имеют повторения по соответствующей аналитике в рамках одного календарного дня. Проанализируем структуру основного запроса, с которым мы будем работать:
ВЫБРАТЬ
уатПутевойЛист.Ссылка КАК Ссылка,
уатПутевойЛист.Дата КАК Дата,
уатПутевойЛист.ТранспортноеСредство КАК ТранспортноеСредство,
уатПутевойЛист.Пассажир КАК Пассажир,
уатПутевойЛист.Водитель1 КАК Водитель1
ИЗ
Документ.уатПутевойЛист КАК уатПутевойЛист
ГДЕ
уатПутевойЛист.Дата МЕЖДУ &ДатаН И &ДатаК
И уатПутевойЛист.Рассчитан = ИСТИНА
Этот способ является наиболее быстрым в реализации и наглядным. Мы добавим в секцию ГДЕ логическую конструкцию, которая будет проверять наличие других записей с такими же параметрами. Разберем по шагам логику этого условия.
Для того чтобы отобрать дубли по транспортному средству, нам нужно убедиться, что в базе существует более одной записи с таким же ТранспортноеСредство в тот же день (НАЧАЛОПЕРИОДА(Дата, ДЕНЬ)). Рассмотрим пример реализации такого условия:
И (НЕ &ТолькоДублиАвтомобилей
ИЛИ уатПутевойЛист.ТранспортноеСредство В (
ВЫБРАТЬ
Т.ТранспортноеСредство
ИЗ
Документ.уатПутевойЛист КАК Т
ГДЕ
Т.Дата МЕЖДУ &ДатаН И &ДатаК
И Т.Рассчитан = ИСТИНА
СГРУППИРОВАТЬ ПО
Т.ТранспортноеСредство,
НАЧАЛОПЕРИОДА(Т.Дата, ДЕНЬ)
ИМЕЮЩИЕ
КОЛИЧЕСТВО(Т.Ссылка) > 1
)
)
В данном коде мы используем оператор ИЛИ в связке с параметром. Если галочка ТолькоДублиАвтомобилей не установлена (значение Ложь), то выражение НЕ &ТолькоДублиАвтомобилей становится Истиной, и все условие выполняется для каждой строки. Если же галочка установлена, в действие вступает вторая часть условия — проверка вхождения ТС в список задублированных.
Для повышения производительности на больших объемах данных (например, когда количество путевых листов превышает десятки тысяч) лучше использовать оператор ВЫБРАТЬ 1 и СУЩЕСТВУЕТ. Проанализируем, как можно переписать условие для пассажиров:
И (НЕ &ТолькоДублиПассажиров
ИЛИ 1 В (
ВЫБРАТЬ ПЕРВЫЕ 1
1
ИЗ
Документ.уатПутевойЛист КАК Т_Дубль
ГДЕ
Т_Дубль.Пассажир = уатПутевойЛист.Пассажир
И НАЧАЛОПЕРИОДА(Т_Дубль.Дата, ДЕНЬ) = НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, ДЕНЬ)
И Т_Дубль.Ссылка <> уатПутевойЛист.Ссылка
И Т_Дубль.Рассчитан = ИСТИНА
)
)
Важный нюанс: Обратите внимание на условие Т_Дубль.Ссылка <> уатПутевойЛист.Ссылка. Оно необходимо для того, чтобы подзапрос не нашел сам себя. Мы ищем любую другую запись, отличную от текущей, но с тем же пассажиром и той же датой.
Если отчет формируется слишком медленно, рекомендуется отказаться от подзапросов в секции ГДЕ и перейти к использованию пакета запросов с временными таблицами. Рассмотрим, как это сделать структурно:
ВТ_Дубли.ЛЕВОЕ СОЕДИНЕНИЕ) с ВТ_Дубли.Количество из ВТ_Дубли не заполнено, значит запись не является дублем).Пример запроса для получения временной таблицы дублей:
ВЫБРАТЬ
уатПутевойЛист.ТранспортноеСредство КАК ТранспортноеСредство,
НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, ДЕНЬ) КАК ПериодДень
ПОМЕСТИТЬ ВТ_ДублиАвто
ИЗ
Документ.уатПутевойЛист КАК уатПутевойЛист
ГДЕ
уатПутевойЛист.Дата МЕЖДУ &ДатаН И &ДатаК
СГРУППИРОВАТЬ ПО
уатПутевойЛист.ТранспортноеСредство,
НАЧАЛОПЕРИОДА(уатПутевойЛист.Дата, ДЕНЬ)
ИМЕЮЩИЕ
КОЛИЧЕСТВО(уатПутевойЛист.Ссылка) > 1
;
Помимо фильтрации данных, пользователю часто важно видеть не только сам факт дубля, но и понимать, какие именно записи конфликтуют. Выясним, как улучшить отчет с помощью Условного оформления:
ЭтоДубль (тип Булево), которое будет рассчитываться на основании вашего запроса.ЭтоДубль равно ИСТИНА, то устанавливать Цвет фона — светло-красный.Также стоит учитывать специфику уатПутевойЛист. В некоторых случаях дублем считается не совпадение календарного дня, а реальное пересечение временных интервалов работы. Если бизнес-логика требует именно такого подхода, в подзапросе следует сравнивать периоды: Т_Дубль.ДатаВыезда < уатПутевойЛист.ДатаВозвращения И Т_Дубль.ДатаВозвращения > уатПутевойЛист.ДатаВыезда. Это позволит найти путевые листы, которые физически «накладываются» друг на друга по времени работы одного автомобиля.
Подводя итог, отметим, что выбор метода (простой подзапрос или временные таблицы) зависит от предполагаемого объема данных. Для оперативного анализа за небольшой период (день или неделя) вполне достаточно решения с коррелированным подзапросом в ГДЕ, предложенного в обсуждении на форуме.