В процессе поддержки старых конфигураций или при анализе чужого кода программисты часто натыкаются на странную конструкцию в тексте запроса: ГДЕ 1=1 или прямо в параметрах виртуальных таблиц, например, РегистрНакопления.Остатки(&Дата, 1=1...). На первый взгляд это кажется программным мусором или ошибкой, так как выражение "единица равна единице" всегда истинно и не несет никакой фильтрующей нагрузки. Однако за этим "окурком", как выразились на форуме, стоит определенная логика. В этой статье мы подробно разберем, откуда берется этот прием, как он работает и чем его заменить в современном коде.
Это самая частая причина появления 1=1. Представим ситуацию, когда пользователь на форме отчета выбирает различные фильтры. Программисту нужно собрать текст запроса программно, добавляя условия только для тех полей, которые заполнены. Рассмотрим типичный "ленивый" алгоритм конкатенации строк:
ТекстЗапроса = "ВЫБРАТЬ * ИЗ Справочник.Номенклатура ГДЕ 1=1";
Если ЗначениеЗаполнено(ВидНоменклатуры) Тогда
ТекстЗапроса = ТекстЗапроса + " И ВидНоменклатуры = &Вид";
КонецЕсли;
Если ЗначениеЗаполнено(Производитель) Тогда
ТекстЗапроса = ТекстЗапроса + " И Производитель = &Производитель";
КонецЕсли;
Проанализируем ситуацию: если бы мы не написали 1=1, то первое условие (Вид номенклатуры) должно было бы начинаться со слова ГДЕ, а все последующие — со слова И. Программисту пришлось бы добавлять лишние проверки: "а не является ли это условие первым?". Использование 1=1 позволяет сделать алгоритм линейным — мы всегда просто прибавляем " И НашеУсловие" к базовой строке. Это экономит время разработчика, хотя и считается признаком не самого качественного кода (так называемого "говнокода").
Разберем еще один сценарий, упомянутый участниками обсуждения. Иногда конструкция 1=1 служит якорем для функции СтрЗаменить(). Разработчик оставляет в запросе "заплатку", которую позже заменяет на реальное условие в зависимости от контекста выполнения программы.
// В конфигураторе написан запрос:
// ГДЕ Склад = &Склад И 1=1
Если УсловиеПоГруппе Тогда
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "1=1", "Номенклатура В ИЕРАРХИИ(&Группа)");
КонецЕсли;
Хотя такой подход работает, он опасен. Если в запросе встретится еще одна единица или похожее сочетание символов, замена может пройти некорректно. Как верно заметили в сообщении №6, гораздо правильнее использовать уникальные параметры-маркеры, например, &ТекстУсловия, которые точно не встретятся в теле запроса случайно.
Посмотрим на ситуацию со стороны разработчика баз данных. При ручном написании и тестировании запросов в консоли, использование 1=1 позволяет быстро закомментировать любое "реальное" условие, не заботясь о том, что оно стоит сразу после ГДЕ.
Кроме того, важно помнить, что Конструктор запросов 1С вполне лояльно относится к таким конструкциям. Если вы напишете в условии 1=1, конструктор не "выбросит" его и не сломает синтаксис, в отличие от некоторых сложных вставок или некорректно переданных параметров. Это делает конструкцию удобной для временных решений.
Выясним причину опасений многих разработчиков: не замедляет ли это работу базы данных? Процессор ведь должен сравнивать эти единицы для каждой строки выборки?
На самом деле, современные СУБД (MS SQL Server, PostgreSQL), на которых работает 1С, обладают мощными оптимизаторами запросов. Еще на этапе подготовки плана выполнения запроса (препроцессинга) оптимизатор видит, что 1=1 — это тавтология, которая всегда истинна. СУБД просто выбрасывает это условие из финального плана исполнения. Это никак не влияет на скорость получения данных и не нагружает сервер. Таким образом, с технической точки зрения 1=1 — это "бесплатная" операция.
Рассмотрим подробнее и обратную ситуацию. Зачем может понадобиться заведомо ложное условие 1=0? Рассмотрим два основных кейса:
ГДЕ 1=0 вернет ноль строк, но сохранит все колонки и их типы.1=1, условие 1=0 служит базой для наращивания фильтров через логическое "ИЛИ". (1=0 ИЛИ Условие1 ИЛИ Условие2).Проанализируем ситуацию: если мы хотим следовать принципам Clean Code и избегать "запахов кода", нам следует отказаться от 1=1 в пользу более элегантных методов. Современный стандарт разработки в 1С предполагает использование массивов для сборки условий.
Рассмотрим правильный алгоритм формирования условий:
МассивУсловий = Новый Массив;
Если ЗначениеЗаполнено(ВидНоменклатуры) Тогда
МассивУсловий.Добавить("ВидНоменклатуры = &Вид");
КонецЕсли;
Если ЗначениеЗаполнено(Склад) Тогда
МассивУсловий.Добавить("Склад = &Склад");
КонецЕсли;
Если МассивУсловий.Количество() > 0 Тогда
ТекстУсловий = СтрСоединить(МассивУсловий, " И ");
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ГдеТутУсловия", "ГДЕ " + ТекстУсловий);
Иначе
ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ГдеТутУсловия", "");
КонецЕсли;
Преимущества этого метода:
1=1 в тексте.И или ГДЕ в начале/конце строки.СтрСоединить).Если вы встретили 1=1 в старом отчете — не пугайтесь. Это легаси-код, который помогал программистам прошлого века быстро и просто собирать запросы "на лету". Он не вредит производительности, но в новом коде его лучше избегать. Мы рекомендуем использовать метод сборки через Массив и СтрСоединить — это покажет ваш профессионализм и сделает код удобным для рефакторинга в будущем.