gifts2017

NULL, да не NULL

Опубликовал Алексей Мутовкин (mrWatson) в раздел Программирование - Практика программирования

Если вы пользуетесь в запросе конструкциями вида

... ГДЕ Продукция.Родитель = &А ИЛИ Продукция.Родитель.Родитель = &А ИЛИ ...

Если вы пользуетесь в запросе конструкциями вида

... ГДЕ Продукция.Родитель = &А ИЛИ Продукция.Родитель.Родитель = &А ИЛИ ...

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

Например

Справочники.Номенклатура.ПустаяСсылка().Родитель

- это пустая ссылка.
В запросе всё немного не так.

Родитель корневого элемента будет пустая ссылка, а все вышестоящие родители будут равны NULL.

Такой запросец (имитирует обращение к предку второго уровня коренвого элемента, т.к. предок первого уровня это пустая ссылка)

ВЫБРАТЬ
    (ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель

вернет NULL.

Что интересно, SQL запрос

ВЫБРАТЬ
    (ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель.Родитель

тоже вернет NULL.

Хотя, казалось бы, он эквивалентен запросу

ВЫБРАТЬ
    (NULL).Родитель

который приводит к ошибке.

Дальше еще интереснее.
Вот такой незамысловатый запрос

 

ВЫБРАТЬ
    ВЫБОР
        КОГДА НЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) В (
                NULL
              )
        ТОГДА 1
        ИНАЧЕ 2
    КОНЕЦ


вернет 1, ну действительно, вроде логично. Хотя операции сравнения с NULL вегда возвращают ЛОЖЬ и необходимо использовать конструкцию ЕСТЬ NULL.

Но с какого-то перепугу

 

ВЫБРАТЬ
    ВЫБОР
        КОГДА НЕ ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) В (
                (ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель
              )
        ТОГДА 1
        ИНАЧЕ 2
    КОНЕЦ


возвращает 2.

Кстати, если в двух последних запросах В заменить на В ИЕРАРХИИ, то первый запрос так и будет возвращать 1, а второй запрос начнет сыпать ошибку.

Подводя итог: обращение к родителям вышестоящего уровня в запросе может привести к псевдо-NULL значениям, которые ведут себя не совсем как NULL. Хотя для них операция ЕСТЬ NULL будет истина. Чтоб оградить себя от подобных казусов, все обращения к "дедам", "прадедам" и т.д. элементов справочников следует заключать в конструкцию ISNULL.

P.S. Не благодарите за ваше острое желание проверить тексты запросов, содержащих Родитель.Родитель

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Сергѣй Батанов (baton_pk) 27.08.15 13:09
операции сравнения с NULL вегда возвращают ЛОЖЬ

Это ересь, за которую надо сжигать на кострах.

цитата с ИТС:
Любая операция сравнения двух значений, в которой участвует хотя бы одно значение NULL, дает результат, аналогичный значению Ложь.

АНАЛОГИЧНЫЙ значению Ложь, но не Ложь.
Восьмой; Evil Beaver; JohnyDeath; mrDSide; kuzyara; GusevNA; denis_aka_wolf; Yashazz; kuntashov; Magnastrag; awk; vano-ekt; +12 Ответить
2. Александр Анисков (vandalsvq) 27.08.15 14:29
(0), Справочник.Родитель.Родитель в запросе, если Справочник.Родитель = NULL не есть тоже самое что NULL.Родитель, хотя бы потому что происходит следующее:
текст запроса вроде

ВЫБРАТЬ Т.Родитель.Родитель КАК Родитель
ИЗ Справочник.Контрагенты КАК Т


Преобразуется в запрос вида

ВЫБРАТЬ Т2.Родитель КАК Родитель
ИЗ Справочник.Контрагенты КАК Т
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контаргенты КАК Т2
ПО Т.Родитель = Т2.Ссылка


все это называется "неявное соединение"
3. Алексей Мутовкин (mrWatson) 27.08.15 15:46
(2) vandalsvq, понятно,но что мешало при левом соединении использовать isnull, было бы логично видеть пустую ссылку
4. Иван Иванов (Famza) 28.08.15 08:33
ВЫБРАТЬ
(ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель
вернет NULL.


Хотя, казалось бы, он эквивалентен запросу

ВЫБРАТЬ
(NULL).Родитель

Если следовать вашей логике, получается, что ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) это NULL?
Или я что-то упустил в языке программирования 1С? Можете указать часть-номер_страницы из ЖКК или ссылку на ресурсе http://its.1c.ru/?
5. Валерий К (klinval) 28.08.15 09:20
(4) Famza, Прикольное у вас цитирование:
Вместо:
ВЫБРАТЬ
(ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель
вернет NULL.

Что интересно, SQL запрос

ВЫБРАТЬ
(ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель.Родитель
тоже вернет NULL.

Хотя, казалось бы, он эквивалентен запросу

ВЫБРАТЬ
(NULL).Родитель

Вы цитируете:
ВЫБРАТЬ
(ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель
вернет NULL.

Хотя, казалось бы, он эквивалентен запросу

ВЫБРАТЬ
(NULL).Родитель

И получается, что автор имел ввиду не то что ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка) это NULL а то что ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)).Родитель это NULL...

А что касается самой публикации: мне вроде ни разу не приходилось пользоваться конструкцией Родитель.Родитель.Родитель.... т.к. я обычно пользуюсь конструкцией:
ГДЕ Родитель В ИЕРАРХИИ(&Родитель)
6. Ivan Khorkov (vano-ekt) 31.08.15 11:00
Если вы пользуетесь в запросе конструкциями вида
... ГДЕ Продукция.Родитель = &А ИЛИ Продукция.Родитель.Родитель = &А ИЛИ ...

то оторвать бы вам руки :-D
7. Алексей Мутовкин (mrWatson) 31.08.15 12:38
(5) klinval, (6) vano-ekt,
А если нужно выбрать элементы внутри папки, лежащие ровно на заданной глубине иерархии?


8. Андрей Овсянкин (Evil Beaver) 31.08.15 13:44
Не нравится мне эта статья, и даже лень формулировать почему именно
DrAku1a; baton_pk; JohnyDeath; mrDSide; denis_aka_wolf; kuntashov; zqzq; Xershi; +8 Ответить 1
9. Александр Анисков (vandalsvq) 31.08.15 15:12
(7) mrWatson, значит у вас неверно выстроена архитектура приложения. Запросы не должны зависеть от данных которые они собирают. Это чуть ли не аксиома.
В идеале запрос надо писать так чтобы не было ни одной идеи смотреть данные.
10. Xer shi (Xershi) 31.08.15 15:17
(9) vandalsvq, а если заказчик хочет видеть иерархию и ТЗ дает такое. Что вы будете делать?
11. Александр Анисков (vandalsvq) 31.08.15 15:54
(10) Xershi, группировка по иерархии не помогает? Настройками вывести на форму чтобы сохранили какие уровни нужны тоже? Или задачу более подробно опишите.
А вообще хорошая архитектура - это сложно, так же сложно как удобная форма, особенно когда речь идет про 1С )))))
12. Алексей Лапицкий (Lapitskiy) 31.08.15 18:24
"Ученые скрестили слона и слона. Не для научных целей, а просто так, позырить"
13. Артем Титеев (a_titeev) 01.09.15 00:56
что еще за "псевдо-NULL"? жесть... Эдгар Кодд должен был перевернуться в гробу со своим третьим правилом реляционных СУБД...
Да, и еще. Напомню, если кто не знает, одно из правил операций с NULL:
Любая операция сравнения с NULL (даже операция «NULL = NULL»), даёт в результате значение «неизвестность» (UNKNOWN). Окончательный результат при этом зависит от полного логического выражения в соответствии с таблицей истинности логических операций. Если сравнение с NULL есть вся логическая операция целиком (а не её часть), то результат её аналогичен FALSE (выражение вида IF <что-то> = NULL THEN <действие1> ELSE <действие2> END IF всегда будет приводить к выполнению действия 2).


Кстати. Полез на всякий случай на Методическую поддержку - http://its.1c.ru/db/metod8dev#content:2590:hdoc. Есть забавная фраза - "Рекомендуется всегда пользоваться разыменованием полей там, где это возможно, чтобы не усложнять запросы лишними конструкциями." Вот отожгли они :) Надо было назвать тот раздел - "Как сделать вялоработающую/неработающую конфигурацию". Ибо именно такие рекомендации и приводят потом к конструкциям "...Родитель.Родитель.Родитель" в запросах. Хотя бывает и хуже. Например, ".Регистратор.Дата" :)
14. Андрей Вахрин (dolter) 01.09.15 12:59
(13) Самое интересное, что "Период" в движении не всегда равен "Регистратор.Дата"... Поэтому это еще не самое страшное )
15. Алексей Кожушко (Rie) 02.09.15 08:35
"...Хотя, казалось бы, он эквивалентен запросу
ВЫБРАТЬ
(NULL).Родитель"
Да нет, не эквивалентен. "Точки" в запросах - это ведь, по сути, соединения, а не "вычислим, а потом ещё раз вычислим".
16. Алексей Мутовкин (mrWatson) 02.09.15 09:45
(8) Evil Beaver,
полезные вещи вообще редко нравятся (рыбий жир, манная каша, закаливание, гимнстика по утрам)
17. Роман Осадченко (cleaner_it) 02.09.15 11:09
(14) dolter, Регистратор.Дата = Период - это один из частных случаев
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа