Перейти к содержанию

BSL187 — Отсутствие проверки на NULL для полей из присоединяемых таблиц

Кратко

Отсутствие проверки на NULL для полей из присоединяемых таблиц

Идентификаторы

Поле Значение
Код правила BSL187
Совместимый псевдоним FieldsFromJoinsWithoutIsNull
Серьёзность WARNING
Включено по умолчанию Да
Реализовано Да
Теги query, correctness

Поведение

  • Публичный идентификатор BSL187 и псевдоним FieldsFromJoinsWithoutIsNull стабильны.
  • Правило сообщает о случаях, описанных на этой странице.
  • Подавления и проектная конфигурация применяются до публикации результата.
  • Для выполнения правила не требуется внешний анализатор или сетевой доступ.

Настройка и подавление

Код BSL### — основной стабильный идентификатор. Совместимый псевдоним принимается в select, ignore и совместимых блоковых комментариях.

[tool.onec-hbk-bsl]
select = ["BSL187"]
ignore = ["FieldsFromJoinsWithoutIsNull"]

Все три семейства подавлений работают для текущей строки и диапазона. Если открывающий комментарий стоит после кода, он действует только на эту строку. Используйте любой один вариант:

  • noqa:
Значение = "пример";  // noqa: BSL187
  • bsl-disable (совместимый вариант):
Значение = "пример";  // bsl-disable: BSL187
  • совместимый BSLLS-вариант:
Значение = "пример";  // BSLLS:FieldsFromJoinsWithoutIsNull-off

Если тот же открывающий комментарий стоит на отдельной строке, он начинает диапазон. Закройте его парным маркером того же семейства:

// noqa: BSL187
// код без этой диагностики
// noqa-enable: BSL187

// bsl-disable: BSL187
// код без этой диагностики
// bsl-enable: BSL187

// BSLLS:FieldsFromJoinsWithoutIsNull-off
// код без этой диагностики
// BSLLS:FieldsFromJoinsWithoutIsNull-on

Чтобы отключить правило до конца файла, не добавляйте закрывающий noqa-enable, bsl-enable или BSLLS:…-on.

Открывающий и закрывающий маркеры должны принадлежать одному семейству.

Описание диагностики

Диагностика проверяет поля из левых, правых, полных соединений, для которых не выполняется проверка с помощью ЕСТЬNULL() или НЕ ЕСТЬ NULL или или ЕСТЬ НЕ NULL.

В запросах нельзя использовать реквизиты из присоединяемых слева или справа таблиц без проверки значений на NULL. Указанное обращение может приводить к ошибкам, если условие соединения не выполнено и нет подходящих записей в левой или правой таблице. В итоге в результате запроса можно получить неожиданные данные и система может повести себя неверным образом.

Важно помнить, что любое сравнение значения NULL с любым другими выражением всегда ложно, даже сравнение NULL и NULL всегда ложно. Смотрите ниже пример подобных неверных сравнений. Поэтому нужно правильно выполнять сравнение с NULL - или через оператор ЕСТЬ NULL или через функцию ЕСТЬNULL().

Также достаточно часто используются левые\правые соединения, хотя данные позволяют использовать внутреннее соединение, в этом случае не нужны проверки на NULL.

Или дополнительные проверки реквизитов выполняются в коде 1С, а не в тексте запроса. Подобные обращения затрудняют чтение кода и рефакторинг кода, т.к. контекст обращения к реквизиту приходится учитывать в нескольких местах. В дополнение нужно учитывать, что простые проверки в запросе выполняются чуть быстрее и проще, чем в интерпретируемом коде 1С.

Указанные проблемы являются одними из самых частых ошибок разработчиков 1С самого разного уровня компетенций.

Примеры

Пример, показывающий проблемы сравнения с NULL - в примере 2 таблицы соединяются заведомо неверно и приведены разные способы сравнения

ВЫБРАТЬ
  ВЫБОР
    КОГДА Левая.Поле2 = 0 ТОГДА "Равно 0 - не работает"
    КОГДА Левая.Поле2 <> 0 ТОГДА "НЕ Равно 0 - не работает"
    КОГДА Левая.Поле2 = NULL ТОГДА "Равно NULL - не работает"
    КОГДА Левая.Поле2 ЕСТЬ NULL ТОГДА "ЕСТЬ NULL - этот вариант работает"
    КОГДА ЕСТЬNULL(Левая.Поле2, 0) = 0  ТОГДА "ЕСТЬNULL() - этот вариант также работает"
    ИНАЧЕ "Иначе"
  КОНЕЦ
ИЗ
  Первая КАК Первая
  ЛЕВОЕ СОЕДИНЕНИЕ Левая КАК Левая
  ПО Ложь // чтобы не было соединения

Подозрительный код обращения к реквизиту присоединенной таблицы

ВЫБРАТЬ
  ДокументыПродажи.Ссылка КАК ДокПродажи,
  РегистрПродажи.Сумма КАК Сумма // здесь ошибка
ИЗ Документ.РеализацияТоваровУслуг КАК ДокументыПродажи
ЛЕВОЕ СОЕДИНЕНИЕ  РегистрНакопления.Продажи КАК РегистрПродажи
ПО ДокументыПродажи.Ссылка = РегистрПродажи.Документ
Правильно
ВЫБРАТЬ
  ДокументыПродажи.Ссылка КАК ДокПродажи,
  ЕстьNULL(РегистрПродажи.Сумма, 0) КАК Сумма
ИЗ Документ.РеализацияТоваровУслуг КАК ДокументыПродажи
ЛЕВОЕ СОЕДИНЕНИЕ  РегистрНакопления.Продажи КАК РегистрПродажи
ПО ДокументыПродажи.Ссылка = РегистрПродажи.Документ
Также правильно
ВЫБРАТЬ
  ДокументыПродажи.Ссылка КАК ДокПродажи,
  ВЫБОР КОГДА РегистрПродажи.Сумма Есть NULL ТОГДА 0
  ИНАЧЕ  РегистрПродажи.Сумма
  КОНЕЦ КАК Сумма
ИЗ Документ.РеализацияТоваровУслуг КАК ДокументыПродажи
ЛЕВОЕ СОЕДИНЕНИЕ  РегистрНакопления.Продажи КАК РегистрПродажи
ПО ДокументыПродажи.Ссылка = РегистрПродажи.Документ
И еще возможный вариант
ВЫБРАТЬ
  ДокументыПродажи.Ссылка КАК ДокПродажи,
  РегистрПродажи.Сумма КАК Сумма
ИЗ Документ.РеализацияТоваровУслуг КАК ДокументыПродажи
ЛЕВОЕ СОЕДИНЕНИЕ  РегистрНакопления.Продажи КАК РегистрПродажи
ПО ДокументыПродажи.Ссылка = РегистрПродажи.Документ
ГДЕ
    РегистрПродажи.Документ ЕСТЬ НЕ NULL
    //или НЕ РегистрПродажи.Документ ЕСТЬ NULL
Последний вариант - не самый лучший, т.к. в нем фактически эмулируется внутреннее соединение. И проще явно указать ВНУТРЕННЕЕ СОЕДИНЕНИЕ вместо использования левого соединения с проверкой ЕСТЬ НЕ NULL или НЕ ЕСТЬ NULL

Источники