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

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

При разработке отчетов и печатных форм в 1С часто требуется получить данные из табличной части документа и одновременно подтянуть актуальные цены или остатки из регистров сведений. Начинающие разработчики нередко сталкиваются с ошибками платформы: «В условиях соединения запроса не допускается обращение к табличным частям» или сбоями на уровне СУБД вроде «Поле не найдено T3.Fld...».

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

Анализ причин ошибки

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


ВЫБРАТЬ
	ПересчетТоваров.Склад,
	ПересчетТоваров.Товары.(
		Ссылка,
		Номенклатура,
		Количество,
		КоличествоФакт
	)
ИЗ
	Документ.ПересчетТоваров КАК ПересчетТоваров
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних КАК ЦеныНоменклатурыСрезПоследних
	ПО ПересчетТоваров.Товары.Номенклатура.Ссылка = ЦеныНоменклатурыСрезПоследних.Номенклатура.Ссылка

В этом примере допущены сразу несколько критических ошибок:

  1. Использование синтаксиса вложенных таблиц .(...) в соединениях: конструкция с круглыми скобками предназначена исключительно для выборки иерархических структур в режиме обхода дерева результатов. Платформа 1С:Предприятие не умеет использовать поля вложенной таблицы в секции ПО (JOIN) и не может корректно транслировать такие конструкции в SQL-запрос.
  2. Неявные соединения через точку: обращение вида Номенклатура.Ссылка избыточно (ссылочное поле Номенклатура уже содержит ссылку). Лишние обращения через точку порождают скрытые соединения на уровне СУБД и снижают производительность.
  3. Обращение к реквизитам шапки через табличную часть: при попытке переписать запрос разработчики часто пишут ПересчетТоваров.Ссылка.Товары.Количество, что приводит к синтаксической ошибке.

Способ 1. Выборка напрямую из реальной таблицы табличной части документа

Самое простое и быстрое решение — выбрать в секции ИЗ не сам объект документа, а конкретную табличную часть как самостоятельную таблицу: Документ.ПересчетТоваров.Товары.

Посмотрим на правила адресации полей в этом случае:

  1. Реквизиты самой табличной части (Номенклатура, Количество, Характеристика) выбираются напрямую по их имени.
  2. Реквизиты шапки документа (например, Склад, Дата, Организация) выбираются через поле ссылки: ПересчетТоваров.Ссылка.Склад.
  3. В условии соединения поле номенклатуры указывается напрямую: ПересчетТоваров.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура.

Рассмотрим рабочий текст запроса:


ВЫБРАТЬ
	ПересчетТоваров.Ссылка.Склад КАК Склад,
	ПересчетТоваров.Ссылка КАК Документ,
	ПересчетТоваров.НомерСтроки КАК НомерСтроки,
	ПересчетТоваров.Номенклатура КАК Номенклатура,
	ПересчетТоваров.Характеристика КАК Характеристика,
	ПересчетТоваров.Количество КАК Количество,
	ПересчетТоваров.КоличествоФакт КАК КоличествоФакт,
	ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена,
	ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) * (ПересчетТоваров.Количество - ПересчетТоваров.КоличествоФакт) КАК СуммаРасхождения
ИЗ
	Документ.ПересчетТоваров.Товары КАК ПересчетТоваров
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
		&Период,
		ВидЦены = &ВидЦены
	) КАК ЦеныНоменклатурыСрезПоследних
	ПО ПересчетТоваров.Номенклатура = ЦеныНоменклатурыСрезПоследних.Номенклатура
	И ПересчетТоваров.Характеристика = ЦеныНоменклатурыСрезПоследних.Характеристика
ГДЕ
	ПересчетТоваров.Ссылка = &Ссылка

Обратите внимание на важные детали:

  1. Фильтрация виртуальной таблицы: параметры &Период и ВидЦены = &ВидЦены обязательно передаются в скобки среза последних. Если не указать вид цены, запрос вернет дубли строк на каждый зарегистрированный вид цены для данной позиции.
  2. Учет характеристик: если номенклатура ведется в разрезе характеристик, соединение по характеристике обязательно, иначе цена может рассчитаться некорректно.
  3. Функция ЕСТЬNULL: если для номенклатуры цена не установлена, левое соединение вернет NULL. Умножение любого числа на NULL дает NULL, поэтому подставляем 0.

Способ 2. Оптимальный вариант с использованием временных таблиц

Когда документ содержит сотни или тысячи строк, прямое соединение физической таблицы табличной части со срезом последних может приводить к избыточной нагрузке на СУБД. В стандартах разработки 1С рекомендуется использовать пакетный запрос с временной таблицей.

Разберем по шагам, как это работает:

  1. Шаг 1: выбираем строки табличной части конкретного документа и помещаем их во временную таблицу ВТ_ТоварыДокумента.
  2. Шаг 2: индексируем поля, по которым будет выполняться соединение (Номенклатура, Характеристика).
  3. Шаг 3: во втором запросе пакета соединяем временную таблицу со срезом цен, передавая во внутренний фильтр только те товары, которые присутствуют в документе.

Посмотрим на пример пакетного запроса:


ВЫБРАТЬ
	ПересчетТоваров.Ссылка.Склад КАК Склад,
	ПересчетТоваров.Ссылка КАК Документ,
	ПересчетТоваров.НомерСтроки КАК НомерСтроки,
	ПересчетТоваров.Номенклатура КАК Номенклатура,
	ПересчетТоваров.Характеристика КАК Характеристика,
	ПересчетТоваров.Количество КАК Количество,
	ПересчетТоваров.КоличествоФакт КАК КоличествоФакт
ПОМЕСТИТЬ ВТ_ТоварыДокумента
ИЗ
	Документ.ПересчетТоваров.Товары КАК ПересчетТоваров
ГДЕ
	ПересчетТоваров.Ссылка = &Ссылка

ИНДЕКСИРОВАТЬ ПО
	Номенклатура,
	Характеристика
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	Товары.Склад КАК Склад,
	Товары.Документ КАК Документ,
	Товары.НомерСтроки КАК НомерСтроки,
	Товары.Номенклатура КАК Номенклатура,
	Товары.Характеристика КАК Характеристика,
	Товары.Количество КАК Количество,
	Товары.КоличествоФакт КАК КоличествоФакт,
	ЕСТЬNULL(Цены.Цена, 0) КАК Цена,
	ЕСТЬNULL(Цены.Цена, 0) * (Товары.Количество - Товары.КоличествоФакт) КАК СуммаРасхождения
ИЗ
	ВТ_ТоварыДокумента КАК Товары
	ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(
		&Период,
		ВидЦены = &ВидЦены
			И Номенклатура В
				(ВЫБРАТЬ РАЗЛИЧНЫЕ
					ВТ_ТоварыДокумента.Номенклатура КАК Номенклатура
				ИЗ
					ВТ_ТоварыДокумента КАК ВТ_ТоварыДокумента)
	) КАК Цены
	ПО Товары.Номенклатура = Цены.Номенклатура
	И Товары.Характеристика = Цены.Характеристика

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

← На главную