Как отфильтровать номенклатуру по виду во временной таблице запроса 1С

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

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

Анализ исходной задачи

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


Запрос.Текст = 
    "ВЫБРАТЬ
    |    ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
    |    ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры КАК ВидНоменклатуры,
    |    СУММА(ОказаниеУслугиПереченьНоменклатуры.Количество) КАК КоличествоВДокументе,
    |    СУММА(ОказаниеУслугиПереченьНоменклатуры.Сумма) КАК СуммаВДокументе
    |ПОМЕСТИТЬ НоменклатураДокумента
    |ИЗ
    |    Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
    |ГДЕ 
    |    ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка  
    |
    |СГРУППИРОВАТЬ ПО
    |    ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
    |    ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры";

Проблема этого кода заключается в том, что условие ГДЕ ограничивает выборку только по ссылке на документ, но никак не проверяет тип самой номенклатуры. В результате в таблицу НоменклатураДокумента попадают абсолютно все строки табличной части.

Решение проблемы: фильтрация через секцию ГДЕ

Для того чтобы во временную таблицу попадали только материалы, нам необходимо расширить условие в секции ГДЕ. Самым простым и эффективным способом является обращение к реквизиту справочника через точку и сравнение его со значением перечисления. Рассмотрим, как это реализовать:


"ВЫБРАТЬ
|    ОказаниеУслугиПереченьНоменклатуры.Номенклатура КАК Номенклатура,
|    СУММА(ОказаниеУслугиПереченьНоменклатуры.Количество) КАК КоличествоВДокументе
|ПОМЕСТИТЬ НоменклатураДокумента
|ИЗ
|    Документ.ОказаниеУслуги.ПереченьНоменклатуры КАК ОказаниеУслугиПереченьНоменклатуры
|ГДЕ 
|    ОказаниеУслугиПереченьНоменклатуры.Ссылка = &Ссылка
|    И ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ВидыНоменклатуры.Материал)
|СГРУППИРОВАТЬ ПО
|    ОказаниеУслугиПереченьНоменклатуры.Номенклатура";

Разберем, что именно мы изменили. Мы добавили логический оператор И и использовали конструкцию ЗНАЧЕНИЕ(...). Эта функция позволяет обратиться к конкретному объекту метаданных (в данном случае — к значению перечисления) непосредственно внутри текста запроса, не передавая его как внешний параметр через УстановитьПараметр().

Варианты реализации: Параметры против Литералов

Хотя использование ЗНАЧЕНИЕ() выглядит компактно, в некоторых случаях профессиональная разработка требует иного подхода. Рассмотрим два варианта:

  1. Использование ЗНАЧЕНИЕ(): Удобно, когда условие жестко зашито в логику (например, проведение всегда касается только материалов). Это избавляет от лишних строк кода в модуле.
  2. Использование параметров запроса: Если логика фильтрации может меняться (сегодня это материалы, завтра — оборудование), лучше использовать параметр &ВидНоменклатуры.

Пример с параметром:


Запрос.Текст = "ГДЕ ... И ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры = &НужныйВид";
Запрос.УстановитьПараметр("НужныйВид", Перечисления.ВидыНоменклатуры.Материал);

Оптимизация производительности: разбор «обращения через точку»

Давайте проанализируем ситуацию с точки зрения производительности СУБД. Когда мы пишем Номенклатура.ВидНоменклатуры, платформа 1С на уровне SQL-запроса выполняет неявное соединение (LEFT JOIN) основной таблицы с таблицей справочника Номенклатура.

Важные нюансы:

Индексирование временных таблиц

Создание временной таблицы — это только половина дела. Как правило, НоменклатураДокумента создается для того, чтобы в дальнейшем соединить ее с таблицами остатков или цен. Чтобы последующие запросы работали быстро, обязательно индексируйте временную таблицу по полям, по которым будет происходить соединение.

Для этого в конец запроса по созданию временной таблицы добавим команду:


|...
|СГРУППИРОВАТЬ ПО
|    ОказаниеУслугиПереченьНоменклатуры.Номенклатура
|ИНДЕКСИРОВАТЬ ПО
|    Номенклатура";

Без индекса при соединении таблиц объемом в несколько сотен строк вы можете не заметить разницы, но на больших документах (например, в оптовой торговле) отсутствие индекса может привести к существенным задержкам (TimeOut) и блокировкам базы данных.

Особенности группировки данных

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

Типичные ошибки при фильтрации в запросах

Проанализируем распространенные ошибки, которые совершают начинающие разработчики:

  1. Фильтрация в коде 1С после запроса: Иногда разработчики выбирают все данные из запроса в таблицу значений, а затем в цикле удаляют строки с услугами. Это крайне неэффективно, так как увеличивает объем передаваемых данных между сервером СУБД и сервером 1С. Всегда старайтесь фильтровать данные на уровне запроса.
  2. Проверка на пустые ссылки: Если в табличной части документа пользователь не заполнил номенклатуру, условие Номенклатура.ВидНоменклатуры = ... просто отсечет эту строку. Обычно это правильное поведение, но если вам нужно выводить ошибку пользователю о незаполненных данных, лучше сначала проверить документ на заполненность, а потом запускать запрос.
  3. Использование типа справочника вместо перечисления: Если ВидНоменклатуры — это справочник, убедитесь, что вы сравниваете поле именно с нужным элементом, а не пытаетесь найти строку по наименованию.

Итоговый алгоритм действий

Подведем итог. Чтобы правильно отобрать материалы во временную таблицу, выполним следующие шаги:

Шаг 1. Определяем, каким типом является признак «материал/услуга» (перечисление или справочник).

Шаг 2. В тексте запроса в секции ГДЕ добавляем условие связи через точку от поля Номенклатура.

Шаг 3. Используем конструкцию ЗНАЧЕНИЕ() для перечислений или передаем параметр для справочников.

Шаг 4. Добавляем индексирование по ключевому полю (ссылке на номенклатуру) для обеспечения быстродействия всей цепочки запросов.

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

← На главную