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