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