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

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

При разработке механизмов заполнения форм, создании обработок или формировании печатных форм программисты 1С часто сталкиваются с необходимостью извлечь данные из табличной части документа, при этом накладывая фильтр на реквизиты «шапки» этого же документа. Типичный пример — получение строк Заказа клиента, только если он находится в определенном статусе (например, статус не равен «Новый» или «Не согласован»).

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

Вариант 1: Фильтрация данных непосредственно в запросе

Это наиболее правильный подход с точки зрения производительности системы. Если мы заранее знаем, что документы в определенном статусе нам не нужны, логично отсечь их на уровне СУБД, не передавая лишние данные в память сервера приложений 1С. Разберем, как это реализовать, работая с табличной частью.

Когда мы делаем запрос к табличной части (например, Документ.ЗаказКлиента.Товары), у каждой строки есть системное поле Ссылка. Через это поле мы можем обратиться к любому реквизиту основного документа, используя обращение «через точку».

Проанализируем пример кода запроса с использованием конструкции ЗНАЧЕНИЕ() для работы с перечислениями:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказКлиентаТовары.Ссылка КАК ДокументСсылка,
    |	ЗаказКлиентаТовары.Номенклатура КАК Номенклатура,
    |	ЗаказКлиентаТовары.Количество КАК Количество
    |ИЗ
    |	Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
    |ГДЕ
    |	ЗаказКлиентаТовары.Ссылка.Статус <> ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказовКлиентов.Новый)";

РезультатЗапроса = Запрос.Выполнить();

Важные замечания к этому способу:

  1. Использование ЗНАЧЕНИЕ(Перечисление.Имя.Значение) позволяет жестко зафиксировать условие в коде запроса. Это удобно, если логика программы не предполагает динамического изменения фильтра.
  2. Обращение ЗаказКлиентаТовары.Ссылка.Статус создает в SQL-запросе неявное соединение (Left Join) табличной части с таблицей документа. На больших объемах данных это допустимо, но следует помнить об индексации реквизита Статус в метаданных для ускорения поиска.
  3. Если в условии ГДЕ допущена ошибка (например, как в одном из сообщений форума, где забыли указать поле .Статус после .Ссылка), запрос вернет пустой результат или ошибку несоответствия типов, так как Ссылка — это объект, а ЗНАЧЕНИЕ(...) — это конкретный элемент перечисления.

Вариант 2: Передача значения статуса через параметры запроса

Более гибким и профессиональным подходом считается использование параметров. Это избавляет от «хардкода» (жесткого прописывания путей к перечислениям) в тексте запроса и позволяет легко изменять условия фильтрации во встроенном языке.

Рассмотрим, как изменить предыдущий пример:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказКлиентаТовары.Ссылка КАК ДокументСсылка,
    |	ЗаказКлиентаТовары.Номенклатура КАК Номенклатура
    |ИЗ
    |	Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары
    |ГДЕ
    |	ЗаказКлиентаТовары.Ссылка.Статус <> &ИсключаемыйСтатус";

Запрос.УстановитьПараметр("ИсключаемыйСтатус", Перечисления.СтатусыЗаказовКлиентов.Новый);

РезультатЗапроса = Запрос.Выполнить();

Этот метод предпочтителен, если вы планируете выносить логику в общие модули или работать с несколькими возможными статусами одновременно (например, используя оператор В (&СписокСтатусов)).

Вариант 3: Условие во встроенном языке (после запроса)

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

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


// В запросе выбираем статус как отдельное поле
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказКлиентаТовары.Ссылка КАК Ссылка,
    |	ЗаказКлиентаТовары.Ссылка.Статус КАК Статус
    |ИЗ
    |	Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    
    Если Выборка.Статус = Перечисления.СтатусыЗаказовКлиентов.Новый Тогда
        // Здесь мы можем уведомить пользователя
        Сообщить("Документ " + Выборка.Ссылка + " находится в статусе Новый. Обработка невозможна!");
        Продолжить; // Переходим к следующей строке выборки
    КонецЕсли;

    // Выполняем полезные действия с результатом
    СоздатьКнопкуДляСтроки(Выборка);

КонецЦикла;

Важно: Обратите внимание на синтаксис Если Статус <> Новый Тогда. В языке 1С слово Новый является зарезервированным оператором для создания объектов (например, Новый Массив). Поэтому при сравнении всегда следует обращаться к полному имени значения через Перечисления.ИмяПеречисления.Значение.

Оптимальное решение для пользовательского интерфейса (UI/UX)

Если ваша задача — создать динамический интерфейс (например, кнопки для каждой строки ТЧ), но при этом исключить документы в статусе «Новый», рассмотрите комбинированный подход. Выясним причину, по которой пользователь может не увидеть данные, добавив в запрос специальный флаг.

Проанализируем пример запроса с конструкцией ВЫБОР:


Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЗаказКлиентаТовары.Ссылка КАК Ссылка,
    |	ВЫБОР 
    |		КОГДА ЗаказКлиентаТовары.Ссылка.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказовКлиентов.Новый) 
    |		ТОГДА ИСТИНА 
    |		ИНАЧЕ ЛОЖЬ 
    |	КОНЕЦ КАК ЭтоЧерновик
    |ИЗ
    |	Документ.ЗаказКлиента.Товары КАК ЗаказКлиентаТовары";

// При обходе результата:
Если Выборка.ЭтоЧерновик Тогда
    // Рисуем заблокированную кнопку или пишем пояснение
Иначе
    // Рисуем активную кнопку
КонецЕсли;

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

Архитектурный совет: Документы vs Регистры

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

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

Резюмируем:

← На главную