Почему запрос в 1С по номенклатуре и сериям возвращает пустой результат и как это исправить

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

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

Анализ исходной проблемы: невнимательность и «перепутанные» параметры

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


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

Проанализируем условие ГДЕ. Мы видим классическую логическую ошибку, вызванную потерей концентрации: параметру СерияНоменклатуры.Код сопоставляется переменная &КодНоменклатуры, а параметру Номенклатура.Код — переменная &КодСерии. Естественно, система пытается найти серию с кодом номенклатуры и номенклатуру с кодом серии, что в 99% случаев дает пустой результат.

Решение: Всегда проверяйте соответствие имен переменных и полей. Исправленный вариант условия должен выглядеть так:


ГДЕ
    ОтчетПроизводстваЗаСменуПродукция.Номенклатура.Код В(&КодНоменклатуры)
    И ОтчетПроизводстваЗаСменуПродукция.СерияНоменклатуры.Код В(&КодСерии)

Проблема производительности: неявные соединения через точку

Хотя исправление параметров решит проблему «пустого результата», с точки зрения архитектуры 1С такой запрос остается неоптимальным. Разберем, почему. Когда мы пишем ОтчетПроизводстваЗаСменуПродукция.Номенклатура.Код, система на уровне СУБД выполняет неявное левое соединение (LEFT JOIN) с таблицей справочника Номенклатура.

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

  1. Сначала программно получить массив ссылок на нужные элементы номенклатуры и серий по их кодам.
  2. Передать в запрос уже готовые ссылки.

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


ГДЕ
    ОтчетПроизводстваЗаСменуПродукция.Номенклатура В(&МассивСсылокНоменклатура)
    И ОтчетПроизводстваЗаСменуПродукция.СерияНоменклатуры В(&МассивСсылокСерии)

Форматирование строк и лидирующие нули

Выясним еще одну причину, по которой запрос по кодам может не работать, даже если параметры указаны верно. В 1С коды справочников (Номенклатура, СерииНоменклатуры) чаще всего имеют строковый тип и фиксированную длину (например, 9 или 11 символов). Система хранит их с так называемыми «лидирующими нулями» (например, «000000432»).

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


Функция ДополнитьКодНулями(Знач Код, Длина)
    КодСтрокой = СокрЛП(Строка(Код));
    Пока СтрДлина(КодСтрокой) < Длина Цикл
        КодСтрокой = "0" + КодСтрокой;
    КонецЦикла;
    Возврат КодСтрокой;
КонецФункции

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

Использование временных таблиц для больших списков

Если список кодов из вашего текстового файла содержит сотни или тысячи позиций, использование условия В (&Параметр) может привести к деградации производительности СУБД. Проанализируем ситуацию: SQL-серверу приходится строить сложный план запроса для огромного списка значений в операторе IN.

Рассмотрим правильный алгоритм действий для работы с большими объемами данных:

  1. Загрузите данные из файла в ТаблицаЗначений с типизированными колонками.
  2. Передайте эту таблицу в запрос в качестве параметра.
  3. Поместите данные во Временную Таблицу (ВТ).
  4. Создайте индекс по колонке кода во временной таблице.
  5. Выполните внутреннее соединение (ВНУТРЕННЕЕ СОЕДИНЕНИЕ) основной таблицы документа с этой временной таблицей.

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


// Сначала помещаем коды во временную таблицу
ВЫБРАТЬ Код ИЗ &ТЗКодов КАК ТЗКодов ПОМЕСТИТЬ ВТ_Коды;
ИНДЕКСИРОВАТЬ ПО ВТ_Коды.Код;

// Затем соединяем
ВЫБРАТЬ Продукция.Ссылка 
ИЗ Документ.ОтчетПроизводстваЗаСмену.Продукция КАК Продукция
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Коды КАК КодыНом ПО Продукция.Номенклатура.Код = КодыНом.Код;

Типизация данных в Консоли запросов

Посмотрим на технический нюанс работы с инструментами разработчика. Если вы отлаживаете запрос в «Консоли запросов», обратите внимание на тип колонки в списке параметров. Часто по умолчанию консоль определяет введенные цифры как тип Число. Однако поле Код в 1С почти всегда является типом Строка. Сравнение Число = Строка всегда будет ложным, и результат запроса останется пустым. Всегда принудительно устанавливайте тип Строка для параметров-кодов в консоли.

Особенности учета серий в «Отчете производства за смену»

Важно помнить, что в конфигурациях типа УПП (Управление производственным предприятием) или КА 1.1 поле СерияНоменклатуры может быть не заполнено физически, если для конкретной номенклатуры в ее настройках не включен серийный учет. В этом случае, даже если вы передаете верный код серии, запрос ничего не найдет, так как в базе данных поле содержит ПустаяСсылка. Перед написанием запроса убедитесь, что в целевых документах данные о сериях действительно присутствуют.

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

← На главную