В данной заметке разберём конкретный пример конструкции, которую лучше не использовать в запросах, чтобы не удивляться результату СКД.
СКД — это волшебная система. Каждый раз удивляемся, сколько можно сэкономить времени, с умом используя её возможности. Однако, как известно, есть у неё и разные «особенности». И их тоже лучше знать.
Возьмём, к примеру, такую ситуацию.
ВЫБРАТЬ
Валюты.Ссылка КАК Ссылка,
Валюты.Наименование КАК Наименование,
Валюты.Код КАК Код,
Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
ИЗ
Справочник.Валюты КАК Валюты
Есть справочник с наименованием и кодом. Мы хотим вывести его элементы. И по каждому выводим колонку «ОшибкаЗаполнения» (булево). Колонка будет содержать значение Истина, когда Наименование или Код пустое.
Результат выполнения:
Вроде всё хорошо. Но предположим, что нам нужно теперь в полученном отчёте вывести только те записи, у которых «Ошибка заполнения» = Нет.
Накладываем отбор и выводим:
Неожиданный результат, верно?
Но для начала на таком простом запросе лучше самому попробовать добавить условие отбора. Не будем сейчас соревноваться в красоте запроса, а просто представим себя на месте СКД. Как бы она подставила наш отбор «Ошибка заполнения» = Нет?
-
Выносим поле в секцию ГДЕ:
ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = "" -
Оборачиваем в скобки:
ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "") -
Сравниваем с значением отбора:
ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "") = ЛОЖЬ
Получаем такой текст запроса. Это то, чего мы ожидаем увидеть от СКД.
ВЫБРАТЬ
Валюты.Наименование КАК Наименование,
Валюты.Код КАК Код,
Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
ИЗ
Справочник.Валюты КАК Валюты
ГДЕ
(Валюты.Наименование = "" ИЛИ Валюты.Код = "") = ЛОЖЬ
Теперь же нам нужно отловить «реальный» текст запроса. Для этого добавляем в наш отчёт кусочек примитивного кода:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки());
НаборДанных = МакетКомпоновки.НаборыДанных.Получить(0);
КонецПроцедуры
Ставим точку останова в конце процедуры, запускаем отладчик, переоткрываем отчёт и снова формируем его с наложенным отбором «Ошибка заполнения» = Нет
В результате в переменной НаборДанных можно увидеть свойство «Запрос».
Мы для наглядности в самом тексте запроса заменили автоматически генерируемый параметр на его значение, которое можно увидеть в переменной МакетКомпоновки.ЗначенияПараметров.
ВЫБРАТЬ
Валюты.Наименование КАК Наименование,
Валюты.Код КАК Код,
Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
ИЗ
Справочник.Валюты КАК Валюты
ГДЕ
(Валюты.Наименование = "" ИЛИ Валюты.Код = "" = ЛОЖЬ)
В чём ошибка?
Если вернуться к нашим шагам наложения условия, можно понять, что СКД пропустила шаг 2.
-
Выносим поле в секцию ГДЕ:
ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = "" -
Оборачиваем в скобки:
ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "") -
Сравниваем с значением отбора:
ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "") = ЛОЖЬ
Выходит, что логика СКД была такая:
-
Выносим поле в секцию ГДЕ:
ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = "" -
Сравниваем с значением отбора:
ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = "" = ЛОЖЬ
Однако, без оборачивания в скобки, СКД полностью меняет смысл условия. В результате мы и видим такой результат. В поле формула отрабатывает нормально, но вот фильтрация работает неверно.
Интересно, что если данное поле убрать из запроса и вынести в вычисляемые поля СКД, то такой ошибки не будет.
Но что, если вынести поле в вычисляемые для нас не выход? Всё просто, применяем другую конструкцию и вместо:
Валюты.Наименование = ""
ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
пишем
ВЫБОР
КОГДА Валюты.Наименование = "" ИЛИ Валюты.Код = ""
ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК ОшибкаЗаполнения
Не так красиво, но зато теперь СКД точно не накосячит, ведь просто подставит сравнение к концу поля.
Возможно, Вам больше понравится иначе изменить условие запроса, но в данный момент это не принципиально. Главное, при написании подобных запросов помнить про эту «особенность». Ведь лучше не провоцировать СКД.
Замечено давненько. Но сейчас протестировано на платформах: 8.3.12.1595, 8.3.14.1779.