В процессе разработки сложных отчетов или обработок на платформе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью фильтрации данных по типам документов. Типичная ситуация: в регистре накопления (например, ВыручкаИСебестоимостьПродаж) необходимо выделить движения, созданные определенным набором документов. Если таких документов много, запрос превращается в бесконечное перечисление условий через оператор ИЛИ. Рассмотрим, как сделать такой код лаконичным, читаемым и производительным.
Стандартный подход к проверке типа выглядит следующим образом: мы используем оператор ССЫЛКА для каждого типа документа. Проанализируем пример, с которого началась дискуссия:
ВЫБОР
КОГДА ВыручкаИСебестоимостьПродаж.Регистратор ССЫЛКА Документ.РеализацияТоваровУслуг
ИЛИ ВыручкаИСебестоимостьПродаж.Регистратор ССЫЛКА Документ.АктВыполненныхРабот
ИЛИ ВыручкаИСебестоимостьПродаж.Регистратор ССЫЛКА Документ.ОтчетОРозничныхПродажах
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК ЭтоПродажа
Такой код сложно поддерживать: если в систему добавится новый вид документа, его придется дописывать во всех местах, где встречается это условие. Кроме того, визуально запрос становится перегруженным. Разберем способы, как этого избежать.
Самый простой и эффективный способ упростить выражение — воспользоваться функцией ТИПЗНАЧЕНИЯ. В отличие от ССЫЛКА, которая проверяет конкретное соответствие, ТИПЗНАЧЕНИЯ возвращает объект типа Тип, который можно сравнивать. Рассмотрим, как трансформируется наше условие:
ГДЕ
ТИПЗНАЧЕНИЯ(ВыручкаИСебестоимостьПродаж.Регистратор) В (
ТИП(Документ.РеализацияТоваровУслуг),
ТИП(Документ.АктВыполненныхРабот),
ТИП(Документ.ОтчетОРозничныхПродажах)
)
Это выражение значительно короче и понятнее. Проанализируем ситуацию, когда проверка происходит в блоке ВЫБОР...КОГДА. Здесь логика сохраняется та же:
ВЫБОР
КОГДА ТИПЗНАЧЕНИЯ(ВыручкаИСебестоимостьПродаж.Регистратор) В (ТИП(Документ.РеализацияТоваровУслуг), ТИП(Документ.АктВыполненныхРабот))
ТОГДА ...
КОНЕЦ
Важный нюанс: при использовании ТИПЗНАЧЕНИЯ внутри В, 1С формирует SQL-запрос, который сравнивает внутренний идентификатор типа в составном поле. Для СУБД это обычно более простая операция, чем цепочка OR по разным таблицам, особенно если типов много.
Если список документов заранее неизвестен или может меняться в зависимости от настроек программы, лучше вынести типы в параметры запроса. Это сделает запрос универсальным. Проанализируем реализацию в коде 1С:
МассивТипов = Новый Массив;
МассивТипов.Добавить(Тип("ДокументСсылка.РеализацияТоваровУслуг"));
МассивТипов.Добавить(Тип("ДокументСсылка.АктВыполненныхРабот"));
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ * ИЗ РегистрНакопления.ВыручкаИСебестоимостьПродаж КАК Рег
|ГДЕ ТИПЗНАЧЕНИЯ(Рег.Регистратор) В (&МассивТипов)";
Запрос.УстановитьПараметр("МассивТипов", МассивТипов);
Этот метод особенно удобен для саморазвития и написания качественного кода. Вы определяете логику фильтрации один раз в программном коде и передаете её в запрос. Это исключает необходимость "прописывать каждый раз целый текст", о чем упоминалось в обсуждении.
Для "огромных" запросов, где одно и то же условие по типам встречается в разных частях кода, использование ВЫБОР КОГДА может существенно замедлить выполнение. Выясним причину: СУБД вынуждена вычислять тип для каждой строки результата. Рассмотрим более продвинутый метод — использование временной таблицы с признаком типа.
ЛЕВОЕ СОЕДИНЕНИЕ основной таблицы с этой временной таблицей.ЕСТЬ NULL).Посмотрим на пример структуры такого запроса:
// Шаг 1: Подготовка типов (можно передать пустые ссылки нужных документов)
ВЫБРАТЬ ТИПЗНАЧЕНИЯ(ЗНАЧЕНИЕ(Документ.РеализацияТоваровУслуг.ПустаяСсылка)) КАК ТипДокумента
ПОМЕСТИТЬ ВТ_НужныеТипы
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ ТИПЗНАЧЕНИЯ(ЗНАЧЕНИЕ(Документ.АктВыполненныхРабот.ПустаяСсылка))
;
// Шаг 2: Основной запрос
ВЫБРАТЬ
Продажи.Регистратор,
ВЫБОР КОГДА ВТ_НужныеТипы.ТипДокумента ЕСТЬ NULL ТОГДА ЛОЖЬ ИНАЧЕ ИСТИНА КОНЕЦ КАК ЭтоНужныйТип
ИЗ
РегистрНакопления.ВыручкаИСебестоимостьПродаж КАК Продажи
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_НужныеТипы КАК ВТ_НужныеТипы
ПО (ТИПЗНАЧЕНИЯ(Продажи.Регистратор) = ВТ_НужныеТипы.ТипДокумента)
Этот метод позволяет "оперировать признаком", не перегружая основной текст запроса сложными конструкциями. Код становится модульным и легко читаемым.
Разберем ситуацию, когда попытка использовать ССЫЛКА приводит к ошибке: Несовместимые типы "ССЫЛКА" И Регистратор > ССЫЛКА Документ.ЧекККМ. Проанализируем причину этого поведения.
Поле Регистратор в регистрах накопления не является произвольным ссылочным типом. Его составной тип жестко ограничен списком документов, которые в метаданных указаны как регистраторы данного регистра. Рассмотрим цепочку рассуждений:
ЧекККМ не делает движений по регистру ВыручкаИСебестоимостьПродаж (не является его регистратором), платформа 1С на уровне компиляции запроса понимает, что в этом поле никогда не может оказаться ссылка на ЧекККМ.Регистратор ССЫЛКА Документ.ЧекККМ является бессмысленной и ошибочной.ОтчетОРозничныхПродажах. Проверять нужно именно его.Часто возникает вопрос: стоит ли бороться за уменьшение количества букв, если "и так работает"? Проанализируем ситуацию с позиции быстродействия.
Оператор ССЫЛКА в блоке ГДЕ работает очень быстро, так как 1С эффективно транслирует его в SQL. Однако использование ИЛИ между несколькими ССЫЛКА заставляет оптимизатор СУБД строить более сложный план. Если типов 2-3, разницы не будет. Если типов 10-20, конструкция ТИПЗНАЧЕНИЯ В (&Массив) может отработать быстрее.
Важное предостережение: избегайте использования сложных конструкций ВЫБОР КОГДА в секции ВЫБРАТЬ для фильтрации в "огромных" запросах. Лучше сначала отфильтровать данные во временную таблицу через ГДЕ, а уже потом работать с подготовленным результатом. Помните слова из обсуждения: "Многострочность — это не сложность, если писать в столбик". Читаемость кода для человека так же важна, как и скорость для сервера.
Подводя итоги, выделим лучшие практики для упрощения запросов:
ТИПЗНАЧЕНИЯ(Поле) В (ТИП(Тип1), ТИП(Тип2)).ССЫЛКА.Использование этих методов позволит вам писать код, который будет не только компактным, но и профессиональным, обеспечивая стабильную работу системы даже на больших объемах данных.