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