При разработке внешних отчетов на схеме компоновки данных (СКД) часто возникает задача: проанализировать строки табличной части подчиненного объекта (например, спецификации или технологической карты) и вывести в шапку отчета общий признак. Например, признак «ЭтоСуперМаршрут» или «ЭтоКомбинированныйМаршрут», который должен принимать значение «Да», если в детальных строках присутствуют определенные комбинации значений, и «Нет» во всех остальных случаях.
Типичная ошибка при реализации такой задачи — прямое левое или внутреннее соединение основной таблицы с ее табличной частью в одном запросе. Это приводит к размножению (дублированию) строк в отчете. Попытки наложить ограничения на номера строк (например, НомерСтроки = 2 или НомерСтроки > 1) не решают проблему, а лишь маскируют её, приводя к потере данных. Вычисляемые поля СКД на уровне детальных записей также не могут помочь, поскольку они рассчитываются для каждой строки ТЧ отдельно и «не видят» соседние строки.
В этой статье мы подробно разберем два надежных способа решения этой задачи без дублирования строк: с помощью временных таблиц в запросе и с использованием связей наборов данных в СКД.
Представим, что у нас есть справочник СпецификацииУпрУчет с табличной частью МаршрутыПереработки. В ТЧ есть строковое поле МаршрутПереработки, которое может принимать значения "01;01", "01;02", "02;01", "02;02" и т.д.
Нам необходимо вывести отчет, где для каждой технологической карты (спецификации) будет определен признак:
Если мы соединим таблицы напрямую, то для спецификации, у которой есть четыре строки в табличной части, мы получим четыре строки в отчете. Группировки СКД свернут их, но вычисляемые поля на уровне детальных записей отработают некорректно.
Самый надежный способ решить эту задачу на уровне базы данных — предварительно рассчитать нужные признаки в свернутом виде во временной таблице, сгруппировав строки по ссылке на главный объект. В этом случае мы гарантируем, что для каждой спецификации в соединение попадет ровно одна строка.
Рассмотрим по шагам построение такого запроса:
Ссылка и вычисляем наличие признаков с помощью агрегатной функции МАКСИМУМ.Пример реализации запроса в конструкторе:
ВЫБРАТЬ
Маршруты.Ссылка КАК ТехКарта,
МАКСИМУМ(ВЫБОР
КОГДА Маршруты.МаршрутПереработки ПОДОБНО "%01%"
И Маршруты.МаршрутПереработки ПОДОБНО "%02%"
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ) КАК ЕстьКомбинированный,
МАКСИМУМ(ВЫБОР
КОГДА (Маршруты.МаршрутПереработки ПОДОБНО "%01%" И НЕ Маршруты.МаршрутПереработки ПОДОБНО "%02%")
ИЛИ (Маршруты.МаршрутПереработки ПОДОБНО "%02%" И НЕ Маршруты.МаршрутПереработки ПОДОБНО "%01%")
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ) КАК ЕстьНекомбинированный
ПОМЕСТИТЬ ВТ_АнализМаршрутов
ИЗ
Справочник.СпецификацииУпрУчет.МаршрутыПереработки КАК Маршруты
СГРУППИРОВАТЬ ПО
Маршруты.Ссылка
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Спецификации.Ссылка КАК ТехКарта,
Спецификации.Владелец КАК Номенклатура,
Спецификации.Контрагент КАК Клиент,
ВЫБОР
КОГДА ЕСТЬNULL(ВТ_АнализМаршрутов.ЕстьКомбинированный, ЛОЖЬ) = ИСТИНА
И ЕСТЬNULL(ВТ_АнализМаршрутов.ЕстьНекомбинированный, ЛОЖЬ) = ИСТИНА
ТОГДА "Да"
ИНАЧЕ "Нет"
КОНЕЦ КАК ЭтоСуперМаршрут
ИЗ
Справочник.СпецификацииУпрУчет КАК Спецификации
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_АнализМаршрутов КАК ВТ_АнализМаршрутов
ПО ВТ_АнализМаршрутов.ТехКарта = Спецификации.Ссылка
Почему это работает? Агрегатная функция МАКСИМУМ для булевых значений работает как логическое "ИЛИ". Если хотя бы в одной строке спецификации условие вернет ИСТИНА, то и общий итог по этой спецификации для данного признака станет равен ИСТИНА. На выходе из временной таблицы мы имеем строго одну строку на каждую спецификацию со всеми рассчитанными флагами.
Если по каким-то причинам вы не хотите менять структуру основного запроса или он собирается динамически, можно переложить задачу агрегации на процессор компоновки данных 1С.
Для этого мы разделим получение данных на два независимых набора данных:
ВЫБРАТЬ
Маршруты.Ссылка КАК ТехКарта,
ВЫБОР
КОГДА Маршруты.МаршрутПереработки ПОДОБНО "%01%"
И Маршруты.МаршрутПереработки ПОДОБНО "%02%"
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК КоличествоКомбинированных,
ВЫБОР
КОГДА (Маршруты.МаршрутПереработки ПОДОБНО "%01%" И НЕ Маршруты.МаршрутПереработки ПОДОБНО "%02%")
ИЛИ (Маршруты.МаршрутПереработки ПОДОБНО "%02%" И НЕ Маршруты.МаршрутПереработки ПОДОБНО "%01%")
ТОГДА 1
ИНАЧЕ 0
КОНЕЦ КАК КоличествоНекомбинированных
ИЗ
Справочник.СпецификацииУпрУчет.МаршрутыПереработки КАК Маршруты
НаборДанных_Шапка (источник) и НаборДанных_Маршруты (приемник) по полю ТехКарта.КоличествоКомбинированных и КоличествоНекомбинированных с выражением агрегации Сумма(КоличествоКомбинированных) и Сумма(КоличествоНекомбинированных) соответственно.ЭтоСуперМаршрут с выражением:
Выбор Когда КоличествоКомбинированных > 0 И КоличествоНекомбинированных > 0 Тогда "Да" Иначе "Нет" Конец.СКД самостоятельно выполнит соединение наборов данных в памяти, просуммирует показатели по строкам табличной части для каждой технологической карты и выведет корректный результат без дублирования строк в отчете.
Обратите внимание на использование конструкции ПОДОБНО "%01%". Если коды маршрутов в вашей базе данных могут иметь вид "101", "201" или "010", данный оператор выдаст ложноположительное срабатывание. Чтобы этого избежать, старайтесь использовать точное соответствие или проверяйте вхождение с учетом разделителей.
Например, если значения всегда разделены точкой с запятой, можно анализировать строки следующим образом:
ВЫБОР
КОГДА ";" + Маршруты.МаршрутПереработки + ";" ПОДОБНО "%;01;%"
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ
Такой подход гарантирует, что вы найдете именно значение "01", а не "101" или "010".