powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Как быть с ANSI NULLS ?
6 сообщений из 6, страница 1 из 1
Как быть с ANSI NULLS ?
    #32386648
Привет всем!
В стандарте SQL92 присутствует данная фича, которая запрещает (или делает крайне неудобным) использование NULL в сравнениях переменных.
Давайте возьмем пример на M$ SQL 2k...
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
create table Tree(
ID     int identity( 0 , 1 ) primary key,  -- просто ключ
 
Root   int,  -- ссылка на владельца (поле ID); references я писать не стал
 
AData  varchar( 128 )  -- важная информация
 
)

insert into Tree(Root, AData) values (null, 'Level 1')
insert into Tree(Root, AData) values (null, 'Level 2')
insert into Tree(Root, AData) values (null, 'Level 3')
insert into Tree(Root, AData) values ( 0 , 'Level 1.1')
insert into Tree(Root, AData) values ( 0 , 'Level 1.2')
insert into Tree(Root, AData) values ( 1 , 'Level 2.1')
insert into Tree(Root, AData) values ( 1 , 'Level 2.2')
insert into Tree(Root, AData) values ( 2 , 'Level 3.1')
insert into Tree(Root, AData) values ( 2 , 'Level 3.2')

Обычное дерево, не правда ли? Теперь напишем процедуру, которая возвращает первые элементы заданной ветки...
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
set ansi_nulls on  -- ЭТО ВАЖНО!
 
create procedure GetByRoot(
@root int
) as
select * from Tree where Root=@root
go

... и попробуем поднять только корневые:
Код: plaintext
1.
exec GetByRoot null

Ну как успехи?... У меня, например, получается, что элементов без владельца не существует, а это неправда!

Решение существует - надо искать так:
Код: plaintext
select * from Tree where isnull(Root,  0 ) = isnull(@root,  0 )

Что? Опять лажа? Ну конечно, у нас же все с нуля начинается...
Код: plaintext
select * from Tree where isnull(Root, - 1 ) = isnull(@root, - 1 )

Чувствуете, появились "волшебные" цифры?

К чему я веду разговор?
В том же M$ SQL по дефолту стоит SET ANSI_NULLS ON , и это требование стандарта. Но ведь это напрягает, и еще как! Попробуйте создать ту же процедуру, предварительно указав ей set ansi_nulls off - и все начнет работать без всяких isnull. И проблема "волшебных" чисел мгновенно пропадает.

Мне не тяжело ставить set ansi_nulls off , но я не пойму главного - ЗАЧЕМ??? Тем более, если это доросло до стандарта...

Что скажете, знатоки?

P.S. Я не спрашиваю о том, как мне реализовать работу с деревом - я хочу узнать мнение окружаюхих, зачем именно зажгли именно эту звезду под названием "ANSI_NULLS"?
P.P.S. Дома у меня инета нет, так что вернусь к обсуждению в понеденьник... Удачных выходных ;)
...
Рейтинг: 0 / 0
Как быть с ANSI NULLS ?
    #32386872
Hibernate
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
по поводу "волшебных" цифр Вы правы - нехорошо, чтобы они появлялись... Поэтому я обычно пишу вот так:
Код: plaintext
select * from Tree where (Root= @root) Or (@root Is Null And Root Is Null)
по поводу того зачем реализована троична логика. Я могу ошибаться, но я значение NULL воспринимаю как "значение неизвестно". Два неизвестных значения не могут быть равными! Операция их сравнения некорректна (пример есть две гири, вес которых неизвестен, как можно сравнивать их по весу? тоесть результат сравнения двух неизвестных тоже неизвестен).
Поэтому если вы ищете строки с вполне определенными значениями, то условие должно быть одно, а если ищете строки, значения которых неопределены, то условие должно быть другое.

Вот что меня раздражает в MsSql, так это то, что в уникальный столбец нельзя вставить два неизвестных значения - тоесть если мне нужно вставить две записи, значения одного из уникальных полей которых неизвестны на момент вставки, я не могу этого сделать, даже если я точно знаю, что эти значения будут разными, когда они станут известными.
...
Рейтинг: 0 / 0
Как быть с ANSI NULLS ?
    #32387382
Urri
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вообще-то для нахождения корня можно просто:

select * from Tree where Root Is Null

и дело с концом.
Лично я рассматриваю эту операцию как повод иметь для нее свой собственный метод.
Т.е. метод получения корня - отдельно, метод получения узлов, растущих из этого корня - отдельно.
...
Рейтинг: 0 / 0
Как быть с ANSI NULLS ?
    #32387910
To Hibernate:
Спасибо, я начал улавливать смысл. :)

А на счет "вставить две записи, значения одного из уникальных полей которых неизвестны на момент вставки" - это требование кажется мне вполне логичным. Наличие ключа (простого или составного - не суть важно) говорит о том, что он однозначно идентифицирует запись - сам смысл ключа в этом а иначе он не нужен. Так что серверу ты не объяснишь типа "я потом допишу отсутствующую инфу, не переживай". Дело в том, что найти конкретную запись по неполному ключу ты потом просто не сможешь ;)...
...
Рейтинг: 0 / 0
Как быть с ANSI NULLS ?
    #32388175
Hibernate
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2Сергей Базилевич:
Unique Constraint не есть одно и тоже, что и Primary Key - уникальное поле необязательно входит в Key таблицы.

Хотя, конечно, я согласен, что это быстрее всего, мои тараканы :-) И разработчики сервера правы. Хотя явное какое-то несоответствие: когда мы сравниваем NULL c другим NULL - получаем NULL. А вот когда это делает Unique Constraint, то он вполне получает True или False....и у него такой результат получается невзирая ни на какие там всякие установки ANSI NULL...
...
Рейтинг: 0 / 0
Как быть с ANSI NULLS ?
    #32388210
Фотография ASCRUS
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Это точно, с NULL надо быть поаккуратнее. Я например долго не мог вьехать, почему у меня в Sybase ASA проходил следующий CHECK на NULL поля:
Код: plaintext
CHECK((Field1 is null and Field2 is null) or (Field1 =  1  and Field2 is not null))

при заносе значений Field1=NULL и Field2=1 данный CHECK срабатывал, хотя по идее должна быть ошибка. Как выяснилось из BOL, оказывается, назло всем остальным правилам работы с NULL, для CHECK состояние UNKNOW означает TRUE. Условие Field=1 генерировало UNKNOW и условие возвращало TRUE. Так что переписав код все правильно заработало:
Код: plaintext
CHECK((Field1 is null and Field2 is null) or (IsNull(Field1, 0 ) =  1  and Field2 is not null))

С одной стороны это правильно, например есть у меня NULL поле и я проверяю, чтобы оно было в определенных границах:
Код: plaintext
CHECK(Field1 between  1  and  5 )

Логично предположить, что если я указал, что поле может содержать NULL, то значит CHECK не должен содержать в себе лишние проверки на NULL, что и сделано в ASA. С другой стороны забыв об этом можно написать по "привычке" работы с NULL и споткнуться, что я собственного говоря и сделал.
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Проектирование БД [игнор отключен] [закрыт для гостей] / Как быть с ANSI NULLS ?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]