Как упростить проверку типов документов в запросе 1С:Enterprise

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

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

Проблема громоздких условий с оператором ССЫЛКА

Стандартный подход к проверке типа выглядит следующим образом: мы используем оператор ССЫЛКА для каждого типа документа. Проанализируем пример, с которого началась дискуссия:


ВЫБОР
    КОГДА ВыручкаИСебестоимостьПродаж.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
        ИЛИ ВыручкаИСебестоимостьПродаж.Регистратор ССЫЛКА Документ.АктВыполненныхРабот
        ИЛИ ВыручкаИСебестоимостьПродаж.Регистратор ССЫЛКА Документ.ОтчетОРозничныхПродажах
    ТОГДА ИСТИНА
    ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК ЭтоПродажа

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

Решение 1: Использование функции ТИПЗНАЧЕНИЯ и оператора В

Самый простой и эффективный способ упростить выражение — воспользоваться функцией ТИПЗНАЧЕНИЯ. В отличие от ССЫЛКА, которая проверяет конкретное соответствие, ТИПЗНАЧЕНИЯ возвращает объект типа Тип, который можно сравнивать. Рассмотрим, как трансформируется наше условие:


ГДЕ
    ТИПЗНАЧЕНИЯ(ВыручкаИСебестоимостьПродаж.Регистратор) В (
        ТИП(Документ.РеализацияТоваровУслуг),
        ТИП(Документ.АктВыполненныхРабот),
        ТИП(Документ.ОтчетОРозничныхПродажах)
    )

Это выражение значительно короче и понятнее. Проанализируем ситуацию, когда проверка происходит в блоке ВЫБОР...КОГДА. Здесь логика сохраняется та же:


ВЫБОР
    КОГДА ТИПЗНАЧЕНИЯ(ВыручкаИСебестоимостьПродаж.Регистратор) В (ТИП(Документ.РеализацияТоваровУслуг), ТИП(Документ.АктВыполненныхРабот))
    ТОГДА ...
КОНЕЦ

Важный нюанс: при использовании ТИПЗНАЧЕНИЯ внутри В, 1С формирует SQL-запрос, который сравнивает внутренний идентификатор типа в составном поле. Для СУБД это обычно более простая операция, чем цепочка OR по разным таблицам, особенно если типов много.

Решение 2: Передача массива типов через параметры

Если список документов заранее неизвестен или может меняться в зависимости от настроек программы, лучше вынести типы в параметры запроса. Это сделает запрос универсальным. Проанализируем реализацию в коде 1С:


МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("ДокументСсылка.РеализацияТоваровУслуг"));
МассивТипов.Добавить(Тип("ДокументСсылка.АктВыполненныхРабот"));

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

Этот метод особенно удобен для саморазвития и написания качественного кода. Вы определяете логику фильтрации один раз в программном коде и передаете её в запрос. Это исключает необходимость "прописывать каждый раз целый текст", о чем упоминалось в обсуждении.

Решение 3: Профессиональный подход с временными таблицами

Для "огромных" запросов, где одно и то же условие по типам встречается в разных частях кода, использование ВЫБОР КОГДА может существенно замедлить выполнение. Выясним причину: СУБД вынуждена вычислять тип для каждой строки результата. Рассмотрим более продвинутый метод — использование временной таблицы с признаком типа.

  1. Создадим временную таблицу, содержащую нужные нам типы.
  2. Выполним ЛЕВОЕ СОЕДИНЕНИЕ основной таблицы с этой временной таблицей.
  3. В основном выборе будем проверять наличие связи (ЕСТЬ NULL).

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


// Шаг 1: Подготовка типов (можно передать пустые ссылки нужных документов)
ВЫБРАТЬ ТИПЗНАЧЕНИЯ(ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка)) КАК ТипДокумента
ПОМЕСТИТЬ ВТ_НужныеТипы
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ ТИПЗНАЧЕНИЯ(ЗНАЧЕНИЕ(Документ.АктВыполненныхРабот.ПустаяСсылка))
;
// Шаг 2: Основной запрос
ВЫБРАТЬ
    Продажи.Регистратор,
    ВЫБОР КОГДА ВТ_НужныеТипы.ТипДокумента ЕСТЬ NULL ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ КАК ЭтоНужныйТип
ИЗ
    РегистрНакопления.ВыручкаИСебестоимостьПродаж КАК Продажи
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_НужныеТипы КАК ВТ_НужныеТипы
    ПО (ТИПЗНАЧЕНИЯ(Продажи.Регистратор) = ВТ_НужныеТипы.ТипДокумента)

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

Ошибки при работе с полем Регистратор (случай с Чеком ККМ)

Разберем ситуацию, когда попытка использовать ССЫЛКА приводит к ошибке: Несовместимые типы "ССЫЛКА" И Регистратор > ССЫЛКА Документ.ЧекККМ. Проанализируем причину этого поведения.

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

Производительность: что быстрее?

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

Оператор ССЫЛКА в блоке ГДЕ работает очень быстро, так как 1С эффективно транслирует его в SQL. Однако использование ИЛИ между несколькими ССЫЛКА заставляет оптимизатор СУБД строить более сложный план. Если типов 2-3, разницы не будет. Если типов 10-20, конструкция ТИПЗНАЧЕНИЯ В (&Массив) может отработать быстрее.

Важное предостережение: избегайте использования сложных конструкций ВЫБОР КОГДА в секции ВЫБРАТЬ для фильтрации в "огромных" запросах. Лучше сначала отфильтровать данные во временную таблицу через ГДЕ, а уже потом работать с подготовленным результатом. Помните слова из обсуждения: "Многострочность — это не сложность, если писать в столбик". Читаемость кода для человека так же важна, как и скорость для сервера.

Итоги и рекомендации

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

  1. Для простых проверок 2-4 типов используйте ТИПЗНАЧЕНИЯ(Поле) В (ТИП(Тип1), ТИП(Тип2)).
  2. Для динамических фильтров передавайте список типов через параметр-массив.
  3. Всегда проверяйте, является ли документ регистратором для конкретного регистра, прежде чем писать ССЫЛКА.
  4. В больших запросах выносите логику определения типа во временные таблицы, чтобы основной запрос оставался "чистым".

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

← На главную