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