Почему запрос в 1С не выдает значения при использовании временных таблиц и оборотов

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

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

Разбор первой проблемы: Отсутствие псевдонимов агрегатных полей

Проанализируем фрагмент кода из исходного сообщения. Автор помещает результат во временную таблицу следующим образом:


ВЫБРАТЬ
    РаботаОбороты.Период,
    РаботаОбороты.Товар,
    Сумма(РаботаОбороты.ЦенаОборот)
ПОМЕСТИТЬ ВремТабОбщЦена
ИЗ
    РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, ) КАК РаботаОбороты
СГРУППИРОВАТЬ ПО
    РаботаОбороты.Период,
    РаботаОбороты.Товар;

Здесь мы видим критическую ошибку: для поля Сумма(РаботаОбороты.ЦенаОборот) не задан псевдоним (через ключевое слово КАК). Когда 1С создает временную таблицу в базе данных, она должна присвоить каждой колонке имя. Если программист не указал его явно, платформа назначит имя по умолчанию (например, Поле1).

В последующем запросе пакета автор пытается обратиться к этому полю:

ВЫБОР КОГДА ВремТабОбщЦена.ЦенаОбороты ЕСТЬ NULL ТОГДА 0 ИНАЧЕ ВремТабОбщЦена.Цена КОНЕЦ

Поскольку во временной таблице нет поля с именем Цена или ЦенаОбороты, запрос либо выдаст ошибку, либо (в некоторых версиях консолей) вернет пустое значение. Всегда задавайте понятные псевдонимы для агрегатных функций во временных таблицах.

Разбор второй проблемы: Фильтрация в ГДЕ вместо параметров виртуальной таблицы

Рассмотрим условие фильтрации. В исходном запросе используется конструкция:


ГДЕ РаботаОбороты.Продовец = &Продовец

Это одна из самых распространенных ошибок производительности и логики в 1С. Виртуальные таблицы (Обороты, ОстаткиИОбороты) — это не реальные таблицы в БД, а сложные подзапросы, генерируемые платформой. Если мы ставим условие в секции ГДЕ, система сначала выбирает все движения по регистру за период, а уже потом отсеивает их. Если же мы передаем условие в параметры виртуальной таблицы (в четвертый параметр), СУБД делает выборку сразу с учетом фильтра.

Кроме того, при использовании ЛЕВОЕ СОЕДИНЕНИЕ фильтр в секции ГДЕ по полю правой (присоединяемой) таблицы фактически превращает соединение во Внутреннее. Если в правой таблице нет данных, соответствующих фильтру, вся строка основного запроса будет отсечена, и мы получим пустой результат.

Как правильно организовать пакет запросов

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

  1. Создаем первую временную таблицу: Здесь мы собираем агрегированные данные. Обязательно используем параметры виртуальной таблицы для фильтрации по продавцу.
  2. Создаем вторую временную таблицу (при необходимости): Если нам нужно соединить данные из того же регистра, лучше подготовить второй набор данных отдельно, чтобы не перегружать основной запрос сложной логикой соединений.
  3. Выполняем финальное соединение: Соединяем временные таблицы по ключевым измерениям (в нашем случае это Период и Товар).

Посмотрим на пример правильной реализации первого шага:


ВЫБРАТЬ
    РаботаОбороты.Период КАК Период,
    РаботаОбороты.Товар КАК Товар,
    Сумма(РаботаОбороты.ЦенаОборот) КАК СуммаЦена
ПОМЕСТИТЬ ВремТабОбщЦена
ИЗ
    РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, Продовец = &Продовец) КАК РаботаОбороты
СГРУППИРОВАТЬ ПО
    РаботаОбороты.Период,
    РаботаОбороты.Товар;

Нюансы соединения по периоду и измерениям

Выясним причину, по которой данные могут "задваиваться". Это происходит, когда связь между таблицами идет по неполному набору измерений. Например, если в регистре Работа есть измерение Склад, а мы соединяем только по Товару и Периоду, то на один товар в один день может прийтись несколько строк (по разным складам), что приведет к умножению результата суммы.

Проанализируем правила успешного соединения:

Итоговый алгоритм решения

Рассмотрим финальную структуру запроса, которая решит проблему автора:


// Первый запрос пакета - подготовка данных
ВЫБРАТЬ
    Обороты.Период КАК Период,
    Обороты.Товар КАК Товар,
    Сумма(Обороты.ЦенаОборот) КАК ЦенаОборот
ПОМЕСТИТЬ ВремТаб
ИЗ
    РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, Продовец = &Продовец) КАК Обороты
СГРУППИРОВАТЬ ПО
    Обороты.Период,
    Обороты.Товар;

// Второй запрос пакета - получение результата
ВЫБРАТЬ
    ОсновнаяТаблица.Период,
    ОсновнаяТаблица.Товар,
    ЕСТЬNULL(ВремТаб.ЦенаОборот, 0) КАК ИтоговаяЦена
ИЗ
    РегистрНакопления.Работа.Обороты(&Дата1, &Дата2, ДЕНЬ, Продовец = &Продовец) КАК ОсновнаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ ВремТаб КАК ВремТаб
    ПО ОсновнаяТаблица.Период = ВремТаб.Период
    И ОсновнаяТаблица.Товар = ВремТаб.Товар;

Важный совет: Если вы замечаете странное поведение в консоли запросов (данные то есть, то их нет), попробуйте явно очищать менеджер временных таблиц или проверьте, не используются ли в запросе одинаковые псевдонимы для разных таблиц. Также обратите внимание на корректность написания имен полей — опечатка в слове Продовец (вместо Продавец), если она допущена в имени измерения самого регистра, должна быть соблюдена и в запросе, какой бы странной она ни казалась.

Соблюдение этих правил: явные псевдонимы, параметры виртуальных таблиц и проверка на NULL — позволит вам создавать надежные и быстрые запросы, которые всегда возвращают корректные значения.

← На главную