Как ограничить запрос по статусу для конкретного типа документа, не затрагивая остальные документы?

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

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

В этой статье мы подробно разберем, как правильно модифицировать такие запросы, избежав ошибок дублирования строк и падения производительности системы.

Анализ исходной ситуации

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

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

Решение через конструкцию ВЫБОР в секции ГДЕ

Самый быстрый и гибкий способ решения задачи — использование логической конструкции ВЫБОР непосредственно в блоке условий ГДЕ. Это позволяет системе проверять тип документа "на лету" и применять фильтр избирательно.

Разберем по шагам, как это реализовать:

  1. Используем оператор ССЫЛКА для проверки типа объекта.
  2. Если тип совпадает с нужным нам документом, проверяем его статус.
  3. Если тип другой, возвращаем ИСТИНА, чтобы документ прошел фильтрацию.

Пример реализации условия в запросе:


ГДЕ
    ГрафикПлатежей.ДатаПлатежа <= &ДатаПлатежа
    И ВЫБОР
        КОГДА ГрафикПлатежей.ОбъектОплаты ССЫЛКА Документ.ЗаказПоставщику
            ТОГДА ГрафикПлатежей.ОбъектОплаты.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказовПоставщикам.Подтвержден)
        ИНАЧЕ ИСТИНА
    КОНЕЦ

В данном примере, если ОбъектОплаты является заказом поставщику, система проверит его статус. Если же это любой другой документ, условие превратится в ИНАЧЕ ИСТИНА, что позволит записи попасть в итоговую таблицу.

Проблема дублирования строк в динамических списках

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

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

Рекомендации по устранению дублей:

Оптимизация: Использование ОБЪЕДИНИТЬ ВСЕ

Хотя вариант с ВЫБОР в ГДЕ кажется простым, для высоконагруженных систем он может быть неоптимальным. При обращении через точку к полю Статус у составного типа данных, SQL-сервер вынужден генерировать тяжелый запрос с множеством LEFT JOIN ко всем возможным таблицам документов.

Проанализируем более профессиональный подход — использование ОБЪЕДИНИТЬ ВСЕ (UNION ALL). Мы разделяем запрос на два независимых блока:

  1. Выбираем только заказы с нужным статусом.
  2. Выбираем все остальные документы, исключая тип "Заказ".

ВЫБРАТЬ
    ГП.Ссылка,
    ГП.Сумма
ИЗ
    РегистрСведений.ГрафикПлатежей КАК ГП
ГДЕ
    ГП.ОбъектОплаты ССЫЛКА Документ.ЗаказПоставщику
    И ГП.ОбъектОплаты.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыЗаказовПоставщикам.Подтвержден)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ГП.Ссылка,
    ГП.Сумма
ИЗ
    РегистрСведений.ГрафикПлатежей КАК ГП
ГДЕ
    НЕ ГП.ОбъектОплаты ССЫЛКА Документ.ЗаказПоставщику

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

Важные замечания по типам данных

При работе с ССЫЛКА важно точно указывать имя метаданных. Распространенная ошибка — путать ЗаказКлиента и ЗаказПоставщику, или использовать устаревшие названия из старых версий конфигураций (например, ЗаказПокупателя вместо ЗаказКлиента в УТ 11).

Также стоит помнить о функции ВЫРАЗИТЬ. Если вы все же используете обращения через точку, хорошим тоном считается предварительное приведение типа. Это помогает оптимизатору 1С понять, к какой конкретно таблице вы обращаетесь:

ВЫРАЗИТЬ(ГрафикПлатежей.ОбъектОплаты КАК Документ.ЗаказПоставщику).Статус

Это не только ускоряет выполнение, но и предотвращает получение значения NULL там, где вы ожидаете конкретное значение перечисления, что часто становится причиной пустых строк в отчетах.

Подведем итог: для простых задач и небольших баз использование ВЫБОР в ГДЕ является допустимым и быстрым решением. Для крупных систем с большим объемом данных в регистрах планирования лучше прибегнуть к разделению запроса через ОБЪЕДИНИТЬ ВСЕ.

← На главную