Как обратиться к табличной части документа через временную таблицу в 1С?

Программист 1С v8.3 (Управляемые формы)
← На главную

При работе с запросами в 1С часто возникает необходимость использовать временные таблицы для промежуточного хранения данных. Это помогает разбить сложный запрос на более простые этапы, улучшить читаемость кода и оптимизировать производительность. Однако, многие разработчики сталкиваются с проблемой при попытке обращения к вложенным табличным частям документов, ссылки на которые хранятся во временной таблице. Рассмотрим эту ситуацию подробнее и выясним, как правильно работать с такими данными.

В чем состоит проблема прямого обращения к табличным частям из временной таблицы?

Исходная проблема, с которой столкнулся автор, заключалась в попытке получить данные табличной части Товары документа СчетНаОплатуПокупателю, когда во временной таблице ТабСчета хранились только ссылки на эти документы. Запрос выглядел примерно так:


ВЫБРАТЬ
    СчетНаОплатуПокупателюТовары.Номенклатура,
    СчетНаОплатуПокупателюТовары.Количество
ИЗ
    ТабСчета.Ссылка.Товары КАК СчетНаОплатуПокупателюТовары

Такой подход приводит к ошибке, потому что временная таблица (ВТ) ТабСчета «знает» только о тех полях, которые мы в нее явно поместили. В данном случае, мы поместили в нее только поле Ссылка (СчетНаОплатуПокупателю.Ссылка). Временная таблица не сохраняет информацию о том, что эта ссылка относится к документу СчетНаОплатуПокупателю, и уж тем более она не содержит сведений о его структуре, включая табличные части. Для системы это просто набор значений типа «Ссылка». Таким образом, попытка обращения через точку к ТабСчета.Ссылка.Товары является неверной, поскольку у поля Ссылка внутри временной таблицы нет свойства Товары.

Когда мы помещаем СчетНаОплатуПокупателю.Ссылка во временную таблицу, в ней хранится только ссылка на документ, а не сам объект документа со всеми его табличными частями. Временные таблицы содержат только те поля, которые явно указаны в предложении ВЫБРАТЬ запроса ПОМЕСТИТЬ. Они не "знают" о структуре объекта, от которого была получена ссылка, и не могут автоматически раскрыть его табличные части.

Корректный подход: Соединение с табличной частью документа

Наиболее распространенный и правильный подход для работы с табличными частями документов, ссылки на которые хранятся во временной таблице, — это соединение временной таблицы с реальной табличной частью нужного документа во втором пакете запроса. Рассмотрим этот процесс по шагам.

Шаг 1: Создаем временную таблицу с необходимыми ссылками

Сначала мы формируем временную таблицу ТабСчета, содержащую ссылки на те документы СчетНаОплатуПокупателю, которые удовлетворяют определенным условиям. Оригинальный запрос автора уже выполняет эту задачу:


ВЫБРАТЬ
    СчетНаОплатуПокупателю.Ссылка КАК Ссылка
ПОМЕСТИТЬ ТабСчета
ИЗ
    Документ.СчетНаОплатуПокупателю КАК СчетНаОплатуПокупателю
        ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
        ПО СчетНаОплатуПокупателю.Ссылка = РеализацияТоваровУслуг.ДокументОснование
ГДЕ
    СчетНаОплатуПокупателю.Дата >= &Дата
    И РеализацияТоваровУслуг.Проведен
СГРУППИРОВАТЬ ПО
    СчетНаОплатуПокупателю.Ссылка
ИМЕЮЩИЕ
    НЕ СУММА(РеализацияТоваровУслуг.СуммаДокумента) = СчетНаОплатуПокупателю.СуммаДокумента;

В этом запросе мы отбираем счета на оплату покупателю, которые имеют проведенные реализации, но сумма реализованных товаров по этим реализациям не равна общей сумме счета. Результат запроса — список ссылок на документы СчетНаОплатуПокупателю, которые будут помещены в нашу временную таблицу ТабСчета. Важно понимать, что в ТабСчета будет только одно поле — Ссылка.

Шаг 2: Соединяемся с табличной частью документа

После того как временная таблица ТабСчета сформирована, мы можем использовать ее во втором пакете запроса. Для того чтобы получить данные из табличной части Товары, мы должны выполнить соединение нашей временной таблицы ТабСчета с табличной частью самого документа Документ.СчетНаОплатуПокупателю.Товары. Это позволит связать ссылки из временной таблицы с соответствующими записями в табличной части.

Рассмотрим пример корректного соединения:


ВЫБРАТЬ
    СчетНаОплатуПокупателюТовары.Номенклатура,
    СчетНаОплатуПокупателюТовары.Количество
ИЗ
    ТабСчета КАК ТабСчета
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.СчетНаОплатуПокупателю.Товары КАК СчетНаОплатуПокупателюТовары
        ПО ТабСчета.Ссылка = СчетНаОплатуПокупателюТовары.Ссылка

В этом запросе мы делаем следующее:

  1. Обращаемся к нашей временной таблице ТабСчета как к источнику данных.
  2. Соединяем ее с реальной таблицей Документ.СчетНаОплатуПокупателю.Товары. Эта таблица содержит все строки табличной части "Товары" для всех документов "Счет на оплату покупателю".
  3. Условием соединения ПО ТабСчета.Ссылка = СчетНаОплатуПокупателюТовары.Ссылка мы связываем строки временной таблицы с записями в табличной части, где Ссылка (родительский документ табличной части) совпадает со ссылкой из нашей временной таблицы.
  4. В результате получаем выборку Номенклатуры и Количества только для тех товаров, которые относятся к документам, отобранным в первом пакете и помещенным во временную таблицу ТабСчета.

Разница между ВНУТРЕННЕЕ СОЕДИНЕНИЕ и ЛЕВОЕ СОЕДИНЕНИЕ

В приведенном выше примере мы использовали ВНУТРЕННЕЕ СОЕДИНЕНИЕ (INNER JOIN). Давайте разберем, когда уместно использовать его, а когда ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN):

Если после ЛЕВОГО СОЕДИНЕНИЯ вы добавляете условие ГДЕ НЕ ТабСчета.Ссылка ЕСТЬ NULL (как было предложено в одном из сообщений), это фактически превращает ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ СОЕДИНЕНИЕ, поскольку отсекаются все строки, для которых соответствие не было найдено в правой таблице. Поэтому, если вам нужны только совпадения, лучше сразу использовать ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

Пример использования ВЫБРАТЬ В (...)

Хотя соединение является предпочтительным способом, существует также возможность использования подзапроса в условии ГДЕ ... В (...). Это менее производительный, но иногда более наглядный способ для очень простых случаев:


ВЫБРАТЬ
    СчетНаОплатуПокупателюТовары.Номенклатура,
    СчетНаОплатуПокупателюТовары.Количество
ИЗ
    Документ.СчетНаОплатуПокупателю.Товары КАК СчетНаОплатуПокупателюТовары
ГДЕ
    СчетНаОплатуПокупателюТовары.Ссылка В (ВЫБРАТЬ ТабСчета.Ссылка ИЗ ТабСчета КАК ТабСчета)

Этот вариант также будет работать, но его производительность может быть ниже, особенно на больших объемах данных, по сравнению с явным соединением таблиц. Оптимизатору СУБД сложнее определить количество записей во вложенном запросе, что может привести к неоптимальному плану выполнения.

Важные моменты и рекомендации по производительности

  1. Использование временных таблиц: Временные таблицы (ВТ) — мощный инструмент для оптимизации сложных запросов. Они позволяют разделить логику на этапы: сначала отбор необходимых сущностей (в нашем случае — документов), затем работа с их детальными данными (табличными частями). Это особенно эффективно при больших объемах данных, когда формирование ВТ с уже отфильтрованным набором ссылок значительно уменьшает объем данных для последующих операций.

  2. Производительность соединений: Соединение временной таблицы с табличной частью документа является стандартным и наиболее производительным способом. Система управления базами данных (СУБД) хорошо оптимизирована для выполнения операций соединения. Отделение этапа фильтрации документов в отдельный пакет с помещением результатов во временную таблицу позволяет СУБД эффективно индексировать и обрабатывать данные на каждом шаге.

  3. Осторожность с вложенными запросами: Стандарты 1С не рекомендуют делать соединения со вложенными запросами, вместо этого рекомендуется использовать соединения с временными таблицами. Это связано с тем, что оптимизатору СУБД сложно определить количество записей во вложенном запросе, что может привести к неоптимальному плану выполнения. Вложенный запрос ВЫБРАТЬ ТабСчета.Ссылка ИЗ ТабСчета КАК ТабСчета в условии ГДЕ ... В (...) является примером такого подхода, который может быть менее эффективным, чем явное соединение.

Заключение

Итак, чтобы корректно обратиться к табличной части документа, ссылки на который хранятся во временной таблице, всегда используйте механизм соединения. Создайте временную таблицу с необходимыми ссылками, а затем во втором пакете запроса выполните ВНУТРЕННЕЕ СОЕДИНЕНИЕ (или ЛЕВОЕ СОЕДИНЕНИЕ, в зависимости от вашей бизнес-логики) этой временной таблицы с полной таблицей табличной части документа. Этот подход является наиболее гибким, производительным и соответствует лучшим практикам разработки в 1С.

Теперь вы знаете, что временная таблица хранит только те поля, которые в нее явно помещены, и не "знает" о структуре объектов, от которых были получены ссылки. Это понимание является ключевым для правильного построения сложных запросов в 1С.

← На главную