Пост

Не провоцируйте СКД, или пример "как не надо"

Пример того, что не нужно использовать в запросах, чтобы не провоцировать СКД


!!! ОПИСАННОЕ В СТАТЬЕ ПОВЕДЕНИЕ ПОПРАВИЛИ В 8.3.16 !!!
НО ЗДЕСЬ ОПИСАНЫ ПОДХОДЫ ПО ПРОВЕРКЕ ПОВЕДЕНИЯ СКД 👌

Важно понимать, что целью статьи не является классифицировать те или иные конструкции как “документированными” или же нет. И не решать, что использовать “хорошо”, а что “плохо”. А лишь показать пример, как реагирует СКД на данный вид конструкций. И поэтому в заголовке написано: пример “как не надо”. Не потому что это “плохо”, а потому что приводит к конкретной проблеме.

В данной заметке разберём конкретный пример конструкции, которую лучше не использовать в запросах, чтобы не удивляться результату СКД.

СКД — это волшебная система. Каждый раз удивляемся, сколько можно сэкономить времени, с умом используя её возможности. Однако, как известно, есть у неё и разные «особенности». И их тоже лучше знать.

Возьмём, к примеру, такую ситуацию.

1
2
3
4
5
6
7
ВЫБРАТЬ
    Валюты.Ссылка КАК Ссылка,
    Валюты.Наименование КАК Наименование,
    Валюты.Код КАК Код,
    Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
ИЗ
    Справочник.Валюты КАК Валюты

Есть справочник с наименованием и кодом. Мы хотим вывести его элементы. И по каждому выводим колонку «ОшибкаЗаполнения» (булево). Колонка будет содержать значение Истина, когда Наименование или Код пустое.

Результат выполнения:

Результат без отбора

Вроде всё хорошо. Но предположим, что нам нужно теперь в полученном отчёте вывести только те записи, у которых «Ошибка заполнения» = Нет.

Накладываем отбор и выводим:

Результат с отбором

Неожиданный результат, верно?

Но для начала на таком простом запросе лучше самому попробовать добавить условие отбора. Не будем сейчас соревноваться в красоте запроса, а просто представим себя на месте СКД. Как бы она подставила наш отбор «Ошибка заполнения» = Нет?

  1. Выносим поле в секцию ГДЕ:
    ‘ГДЕ Валюты.Наименование = “” ИЛИ Валюты.Код = “”’

  2. Оборачиваем в скобки:
    ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "")

  3. Сравниваем с значением отбора:
    ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "") = ЛОЖЬ

Получаем такой текст запроса. Это то, чего мы ожидаем увидеть от СКД.

1
2
3
4
5
6
7
8
ВЫБРАТЬ
    Валюты.Наименование КАК Наименование,
    Валюты.Код КАК Код,
    Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
ИЗ
    Справочник.Валюты КАК Валюты
ГДЕ
    (Валюты.Наименование = "" ИЛИ Валюты.Код = "") = ЛОЖЬ

Теперь же нам нужно отловить «реальный» текст запроса. Для этого добавляем в наш отчёт кусочек примитивного кода:

1
2
3
4
5
6
7
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    КомпоновщикМакета   = Новый КомпоновщикМакетаКомпоновкиДанных;     
    МакетКомпоновки     = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки());
    НаборДанных         = МакетКомпоновки.НаборыДанных.Получить(0);
    
КонецПроцедуры

Ставим точку останова в конце процедуры, запускаем отладчик, переоткрываем отчёт и снова формируем его с наложенным отбором «Ошибка заполнения» = Нет

В результате в переменной НаборДанных можно увидеть свойство «Запрос».

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

1
2
3
4
5
6
7
8
ВЫБРАТЬ
    Валюты.Наименование КАК Наименование,
    Валюты.Код КАК Код,
    Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения
ИЗ
    Справочник.Валюты КАК Валюты
ГДЕ
    (Валюты.Наименование = "" ИЛИ Валюты.Код = "" = ЛОЖЬ)

В чём ошибка?

Если вернуться к нашим шагам наложения условия, можно понять, что СКД пропустила шаг 2.

  1. Выносим поле в секцию ГДЕ:
    ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = ""

  2. Оборачиваем в скобки:
    ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "")

  3. Сравниваем с значением отбора:
    ГДЕ (Валюты.Наименование = "" ИЛИ Валюты.Код = "") = ЛОЖЬ

Выходит, что логика СКД была такая:

  1. Выносим поле в секцию ГДЕ:
    ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = ""

  2. Сравниваем с значением отбора:
    ГДЕ Валюты.Наименование = "" ИЛИ Валюты.Код = "" = ЛОЖЬ

Однако, без оборачивания в скобки, СКД полностью меняет смысл условия. В результате мы и видим такой результат. В поле формула отрабатывает нормально, но вот фильтрация работает неверно.

Результат с отбором

Интересно, что если данное поле убрать из запроса и вынести в вычисляемые поля СКД, то такой ошибки не будет.

Вычисляемое поле Запрос вычисляемое поле

Но что, если вынести поле в вычисляемые для нас не выход? Всё просто, применяем другую конструкцию и вместо:

Валюты.Наименование = "" ИЛИ Валюты.Код = "" КАК ОшибкаЗаполнения

пишем

1
2
3
4
5
ВЫБОР
   КОГДА Валюты.Наименование = "" ИЛИ Валюты.Код = ""
        ТОГДА ИСТИНА
   ИНАЧЕ ЛОЖЬ
КОНЕЦ КАК ОшибкаЗаполнения

Не так красиво, но зато теперь СКД точно не накосячит, ведь просто подставит сравнение к концу поля.

Возможно, Вам больше понравится иначе изменить условие запроса, но в данный момент это не принципиально. Главное, при написании подобных запросов помнить про эту «особенность». Ведь лучше не провоцировать СКД.

Замечено давненько. Но сейчас протестировано на платформах: 8.3.12.1595, 8.3.14.1779.

Авторский пост защищен лицензией CC BY 4.0 .