[SQL] зачем NULL трактуется так извращенно?
"бенефит" - простота и интуитивность определения поведения СУБД при работе с неопределёнными значениями. ну и стандартность подхода, разумеется
когда видишь что в запросе есть обработка NULL сразу понимаешь зачем это надо
когда видишь что ее там нет, сразу начинаешь думать а что будет с запросом если нет данных
эдакая наглядность дополнительная
вощем наллы точняк нужны
другой вопрос почему СУБД внутри себя автоматически не преобразуют
where column = :valueв
where :value IS NOT NULL AND column = :value) OR (:value IS NULL AND column IS NULLхз почему не преобразуют
может их просто ломает разные обработчики для =,>,< писать...
еще добавлю чтоб не забывали, что в оракле пустая строка и NULL одно и то же
P.S.
чет я совсем туго излагаю свои мысли, надеюсь мя поймут
Сравнения с NULL дают NULL.
Люди, работающие по несколько лет исключительно с базами данных, офигевают, когда узнают, что
NULL or TRUE = TRUE
NULL and TRUE = NULL
Логика есть, я знаю, но она непрозрачна для мозга.
Еще на поверку оказывается, что в SQL нету типа Boolean, более того, БД не понимают, когда хочешь написать
select (1 = 1) from dual
или его аналог - приходится жутко шаманить.
Короче, перестал я понимать философию БД.
select (1 = 1) from dualя вроде не СУБД, но это тоже не понимаю
что ты хочешь в результе получить? результат присвоения единицы к единице?
указатель в памяти что ли?
Но почему же тогда
(отсутствие данных) != (отсутствие данных)
?
Зачем трактовать NULL как какое-то суперзначение, логика работы с которым отличается от логики других значений?
Не хочется думать, во что придется развернуть условие в
select * from table where column1 = :value1 and column2 = :value2 or column3 = :value3
, чтобы получить ожидаемое поведение, и насколько нереально после этого будет понять, что же изначально имелось в виду.
Я хочу получить TRUE.
в SQL нету типа Booleanэгегей, зачем врешь?
стандарт SQL99 определяет тип BOOLEAN
если чего нет в оракле, это не значит что его нет в SQL
с каких эпор оракл стал стандартом SQL ?
Но почему же тогдагыгы
(отсутствие данных) != (отсутствие данных)
?
допустим что отсутствие = отсутсвие
что делать в случае джойна таблиц?
тебе не кажется что такой джойн получается бредом?
select (1 = 1)
Я хочу получить TRUE.кстати, а ты пробовал это на СУБД в которых есть BOOLEAN?
может это как раз и есть TRUE?
например в постгресе
В случае джойна таблиц NULL трактовать как обычное значение.
NULL джойнятся с NULL - вполне логично.
Я к тому, что тестить логику БД выраженями
select (1 = 1) or NULL
не удается. Приходится изгаляться с where.
PS. И я бы даже стерпел такое тупое поведение NULL, но
1. Базовики говорят, что постоянно юзают NVL, чтобы избавляться от NULL-ов.
Спрашивается, зачем реализовано такое неочевидное поведение NULL, если в большинстве случаев людям, использующим БД, приходится использовать костыль в виде NVL, чтобы его обойти?
2. Все можно понять. Я надеялся, что напишу функцию Equal(value1, value2 которая внутри будет правильно сравнивать два NULL-значения, НО
select * from table where Equal(column, :value)
Ораклу не нравится. Подозреваю, что SQL сервер тоже не схавает.
Надо будет, например, приписать сравнение с 1
select * from table where Equal(column, :value) = 1
Вашу мать! И это в 2008 году!
http://sqlbooks.ru/readarticle.aspx?part=09&file=additio...
+
http://sqlbooks.ru/readarticle.aspx?part=09&file=additio...
+
http://sqlbooks.ru/readarticle.aspx?part=09&file=additio...
Короче, перестал я понимать философию БД.Может быть, это как-то поможет =)
Подозреваю, что SQL сервер тоже не схаваетесли не ошибаюсь, там вообще нельзя создать функцию возвращающую boolean
Интересно, какой процент разработчиков БД осознают это все и обходятся без вуду-программинга.
добавлю что это еще способствует думанию про отсутствие данных
когда видишь что в запросе есть обработка NULL сразу понимаешь зачем это надо
когда видишь что ее там нет, сразу начинаешь думать а что будет с запросом если нет данных
эдакая наглядность дополнительная
вощем наллы точняк нужны
другой вопрос почему СУБД внутри себя автоматически не преобразуют
В ответ на:
where column = :value
в
В ответ на:
where :value IS NOT NULL AND column = :value) OR (:value IS NULL AND column IS NULL
хз почему не преобразуют
может их просто ломает разные обработчики для =,>,< писать...
имхо ты сам себе противоречишь
если б база так все разворачивала, то никто б и не думал об "отсутствии данных" - было б тоже самое, чего хочет автор
Не увидел ничего из разряда вуду-программирования. Это достаточно базовые вещи для Оракла, к сожалению (в том смысле, что есть куда более сложных и неочевидных вещей).
NULL джойнятся с NULL - вполне логично.
и что тут логичного? имхо как раз получится фигня (лень пример придумывать)
1. Базовики говорят, что постоянно юзают NVL, чтобы избавляться от NULL-ов.
Спрашивается, зачем реализовано такое неочевидное поведение NULL, если в большинстве случаев людям, использующим БД, приходится использовать костыль в виде NVL, чтобы его обойти?
на счет "в большинстве случаев" ты имхо не прав
ЗЫ касаемо примера:
допустим ты получил имя клиента и хочешь получить по нему что-то нам (пусть будет именно имя, а не ID).
далее допустим, что тебе не повезло и ты 1) получил пустую строку 2) ты на оракле (i.e. ты получил NULL)
по-твоему нормально, что, в твоем варианте, в этом случае ты получишь непустой результат?
ЗЗЫ вообще NULL полезная штука и то что она трактуется именно так имхо правильно... меня вот скажем раздражает ужасно, что в некоторых базах по умолчанию включено такое сравнение, как ты хочешь
Я к тому, что даже эти "базовые", как ты говоришь, вещи сходу не очевидны даже для базовиков с многолетним стажем.
Этого будет ожидать любой нормальный человек (не мыслящий в троичной логике).
Ты в форуме больше трёх лет. Ты всё знаешь про HTTP?
select * from table where column1 = :value1 and column2 = :value2 or column3 = :value3
чтобы оно адекватно NULL-ы обработало?
Представь, что кто-то уже развернул.
Ты сможешь понять, что он имел в виду at a glance?
NULL or TRUE = TRUEи первое и второе - это чисто oracle, а не sql
NULL and TRUE = NULL
...
select (1 = 1) from dual
в sql в первом случае должно быть: null or true - null
по второму должно быть
select 1=1 (без всяких dual-ов) и должно возвращаться true
HTML меня мало интересует.
Общие вещи знаю.
А что, у тебя есть вопросы?
Ну вот ты за 3 года не научился различать HTML и HTTP. Чего ты хочешь от тех "базовиков"?
имхо ты сам себе противоречишьвроде не противоречю
в первой яасти я говорю что троичная логика нужна, что спец. обработка для null нужна
во второй части я говорю что возможно есть один случай когда возможно она не нужна: это равенство
но потом я сообразил про джойны и этот случай тоже отпал, ибо джойнить по наллам это бред
если бы токо можно было отличать джойн от чиста сравнения
как-то так:
where column ~= :value
ну тойсть есть спец. операция ~= которая может наллы сравнивать
но это же получается ненужный сахар, который еще и к путанице может привести
придумал еще вариант:
where NVL(column, SPECIAL_VALUE_THAT_NEVER_CAN_OCCURS_IN_THIS_COLUMN)
= NVL(:value, SPECIAL_VALUE_THAT_NEVER_CAN_OCCURS_IN_THIS_COLUMN)
и первое и второе - это чисто oracle, а не sqlот тебя не ожидал
в sql в первом случае должно быть: null or true - null
даже по обычной домашней логике: правда или всечтоугоднохотьчтотохотьничто = правда
Говорю же, с вебом дело мало имел, да и речь не о нем.
Я знаю их настолько, насколько мне это сейчас нужно.
Понадобится лучше - будет лучше.
от туда же
Boolean datatype inconsistency
The ISO SQL:1999 standard introduced the Boolean datatype to SQL.[20] The Boolean datatype, as defined by the standard, can hold the truth values TRUE, FALSE, and UNKNOWN. Null is defined in this one instance as equivalent to the truth value UNKNOWN.
This "null equals UNKNOWN truth value" proposition introduces an inconsistency into SQL 3VL. One major problem is that it contradicts a basic property of nulls, the property of propagation. Nulls, by definition, propagate through all SQL expressions. The Boolean truth values do not have this property. Consider the following scenarios in SQL:1999, in which two Boolean truth values are combined into a compound predicate. According to the rules of SQL 3VL, and as shown in the 3VL truth table shown earlier in this article, the following statements hold:
( TRUE OR UNKNOWN ) → TRUE
( FALSE AND UNKNOWN ) → FALSE
However, because nulls propagate, treating null as UNKNOWN results in the following logical inconsistencies in SQL 3VL:
( TRUE OR NULL ) → NULL ( = UNKNOWN )
( FALSE AND NULL ) → NULL ( = UNKNOWN )
The SQL:1999 standard does not define how to deal with this inconsistency, and results could vary between implementations. Because of these inconsistencies and lack of support from vendors the SQL Boolean datatype did not gain widespread acceptance. Most SQL DBMS platforms now offer their own platform-specific recommendations for storing Boolean-type data.
Если в базе есть клиенты с именем NULL, они и должны получиться.
таких нет конечно же - просто кто-то откуда-то прислал тебе пустую строчку вместо имени
Что тебе не нравится?
Люди, работающие по несколько лет исключительно с базами данных, офигевают, когда узнают, чтовесь тред не читал, но про нетривиальность NULL-а и троичную логику Кузнецов на ВМК в базовом курсе лекций по базам данных рассказывал
code:
NULL or TRUE = TRUE
NULL and TRUE = NULL
Я знаю их настолько, насколько мне это сейчас нужно.Теперь понятно, почему твои базовики мало знают про NULL?
Понадобится лучше - будет лучше.
Тогда ты никого и не получишь
ты недопонял
выбираешь ты не из таблицы с клиентами, а из таблицы где есть на них ссылка, которая может быть NULL
NULL сделали для того, чтобы можно было указывать отсутсвующий внешний индекс и корректно его обрабатывать при JOINах. И пользоваться им надо только в тех колонках таблицы, которые хранят ссылки на внешний индекс. Если ты хранишь NULL в качестве отсутсвующего имени, а потом удивляешься, что всё не интуитивно, то сам себе злобный буратин. Ибо так делать не надо. Если имени нет, то храни там пустую строку. Или FALSE или UNKNOWN, смотря что БД позволяет использовать.
Если имени нет, то храни там пустую строку. Или FALSE или UNKNOWN, смотря что БД позволяет использовать.блин
прочти тред сначала
я ж писал: в оракле пустая строка и NULL это одно и то же
то есть если имени нет, то у тебя токо один вариант: хранить там NULL
Ну это как бы проблема оракла, а не SQL. И вопрос надо ставить не "почему NULL в SQL так нелогично себя ведёт?", а "почему пустая строка так нелогично интерпретируется ораклом?".
Если ты хранишь NULL в качестве отсутсвующего имениотсутствие имени - это и есть null
Ибо так делать не надо. Если имени нет, то храни там пустую строку. Или FALSE или UNKNOWN, смотря что БД позволяет использовать.бред.
непонятно из каких соображений вот такое
table Car (id int, modelId int nullable)
table CarModel (int id, string name)
select car.id as carId, CarModel.Name as modelName from car
join carmodel on car.modelId=carmodel.id
должно отличаться от
table Car (id int, model string nullable)
select car.id as carId, car.model as modelName from car
т.е. совсем не понятно, почему мы в первом случае должны работать с null-ем, а во втором с каким-то мифическим unknown
если бы токо можно было отличать джойн от чиста сравненияМожно принудительно заставить всех при селекте по нескольким таблицам сначала сджойнить все эти таблицы (по синтаксису JOIN а только потом писать WHERE
просто кто-то откуда-то прислал тебе пустую строчку вместо имениПустая строчка и налл - это разные вещи
Если у кого-то в поле "имя" стоит налл, это значит, что у этого клиента не просто пустое имя - а что у этого клиента нет имени вообще.
Соответственно, джойнить в таком случае их действительно будет бредом.
е. совсем не понятно, почему мы в первом случае должны работать с null-ем, а во втором с каким-то мифическим unknownЧто-то я не понял, у тебя там что, появились модели с Id = null?
Если modelId = null, то ты как modelName получишь тот же null, а не то, что там лежит в какой-то мифической строке в таблице моделей по айди null.
Рассмотрим пару таблиц (точный синтаксис SQL не знаю, пишу псевдокод)
create table Role (int id, nullable string name)
insert into Role (1, "Admin")
insert into Role (2, "User")
insert into Role (3, null)
create table User (int id, nullable string name, nullable int roleId)
insert into User (1, "Pentaur2", 1);
insert into User (4, "", 2);
insert into User (5, "", 3);
insert into User (6, "", null);
Можешь на данном примере объяснить, что ты хочешь выбрать и какие проблемы возникли бы, если бы NULL трактовался так, как предлагаю я?
Можешь на данном примере объяснить, что ты хочешь выбрать и какие проблемы возникли бы, если бы NULL трактовался так, как предлагаю я?Это к тебе вопрос, что ты с этим хочешь сделать, и где там у тебя будет сравнение двух null-ов.
В твоём примере я никак не могу увидеть, что с чем ты пытаешься сравнить, и где у тебя возникает проблема.
Если modelId = null, то ты как modelName получишь тот же nullВ том то и дело, в одном случае ты получишь null в результате, а в другом советуют использовать мифический unknown, хотя по смыслу запросы возвращают одно и тоже. Unknown не спасет от обработки null значений, а только путанницы добавит. Не плодите сущностей.
Вариант 1. Получим пары Пользователь, Роль и сравним их:
select
t1.name
from
(select u.id, u.name, r.name role from User u join Role r on (u.roleId = r.id) t1,
(select u.id, u.name, r.name role from User u join Role r on (u.roleId = r.id) t2
where t1.role = t2.role
and t1.id > t2.id;
Name
--------------
NULL
Пока всё хорошо: в наших таблицах таких пользователей нет, что мы и получили.
Вариант 2. Оптимизируем производительность. Сначала получим список ролей с одинаковым названием, а затем для них получим список пользователей:
select name from User u where u.roleId in
(Select r1.id from Role r1, Role r2 where r1.name = r2.name and r1.id >r2.id);
Name
--------------
""
Опа.
К слову при традиционной трактовке NULL оба способа дают одинаковый ответ.
Выведем пользователей у которых роли называются одинаково.Ты извращенец вдвойне.
Во-первых, потому что выбираешь пользователей, у которых роли называются одинаково, а не просто одинаковые.
И во-вторых, потому что считаешь, что у двух пользователей - у первого роль безымянна, а у второго и роли-то нет - одинаковые названия ролей.
select * from User where roleId = (select id from Role where name=:roleName)
если передать в качестве имени роли NULL, я ожидаю получить пользователя , а не получу никого.
Пустая строчка и налл - это разные вещи
пенартур - ты долб
я же написал, что это в случае оракла
ЗЫ ты уже научился правильно произносить SQL?
непрозрачный неадекват кочует из версии в версию ведущих СУБД и люди продолжают ходить по граблям, плеваться и говорить "так написано в СТАНДАРТЕ"?
точный синтаксис SQL не знаю
ну так построй уже свой
Я хочу выбрать всех юзеров с заданной ролью:
code:
select * from User where roleId = (select id from Role where name=:roleName)
если передать в качестве имени роли NULL, я ожидаю получить пользователя , а не получу никого.
А если в качестве имени роли передать, по ошибке, "Админ". То выберется ""
если передать в качестве имени роли NULL, я ожидаю получить пользователя , а не получу никого.И правильно, потому что ты не должен этого хотеть.
Если ты хочешь получить всех пользователей без роли - то ты говоришь "RoleId IS NULL". Если ты хочешь получить всех пользователей с ролью с именем-пустой строкой, и у тебя есть такая роль (но этого ты тоже не должен хотеть то ты в таблицу ролей кладёшь роль не с именем NULL, а с именем '', и потом передаёшь в выражение не null, а пустую строку.
Тебе +1.
Тему можно закрывать.
иногда ты так сильно надоедаешь ...
Оставить комментарий
aleks058
Субж.Почему я не могу написать
передать :value = NULL и получить те значения, которые ожидает любой нормальный человек?
Кто это придумал я нашел, но не могу понять, почему такой непрозрачный неадекват кочует из версии в версию ведущих СУБД и люди продолжают ходить по граблям, плеваться и говорить "так написано в СТАНДАРТЕ"?
Может есть какой-то реальный бенефит, о котором я не знаю?