Nick |
Отправлено: 04.06.2004, 17:42 |
|
Машинист паровоза
Группа: Участник
Сообщений: 247
|
Все этот NULL
Столько проблем с ним
может кто то объснит зачем это надо
или для всех полей объявлять нот нул
что бзабота была не моя
ведь если звезды зажигают значит это для кого-то нужно
одно только визуальное преимущество видел
остальное все недостатки (может только мои) |
|
Admin |
Отправлено: 04.06.2004, 20:58 |
|
Владимир
Группа: Администратор
Сообщений: 1190
|
QUOTE | Столько проблем с ним |
А какие проблемы ?
По моему как раз очень удобно.
И зачаем для всех полей объявлять NOT NULL ?
Представьте себе ситуацию:
Есть 2 таблицы:
Categories — Категории товаров
-------------
ID integer — ключ autoinc
Category varchar(80)
...
и вторая
Goods — товары
-------------
ID integer — ключ autoinc
ID_Cat integer — внешний ключ на поле ID таблицы Categories
MyGoods varchar(30)
....
SQL | ALTER TABLE "Goods" ADD CONSTRAINT "FK_Goods_Category" FOREIGN KEY ("ID_Cat") REFERENCES "Categories" (ID) ON DELETE CASCADE ON UPDATE CASCADE; |
То есть есть товары и есть какие-то категории этих товаров
к которым относятся эти товары.
типа
МОНИТОРЫ: ... ... ... ...
ПРИНТЕРЫ: ... ... ...
...
Если объявить поле ID_Cat как NOT NULL, то товар, который заноситься
в таблицу Goods будет обязательно принадлежать какой-либо
из категорий !
А ведь может быть ситуация, когда товар не должен
относиться ни к одной из категорий, но ограничение внешнего
ключа и NOT NULL не позволят Вам этого сделать !
А если поле ID_Cat будет объявлено как NULL, то в этом случае
товары из таблицы Goods или относятся к какой-либо категории
из таблицы Categories или могут иметь значение NULL,
то есть не относиться ни к одной из категорий.
Тогда и ограничение внешнего ключа (конечно в зависимости
от реальной ситуации) можно записать по другому:
SQL | ALTER TABLE "Goods" ADD CONSTRAINT "FK_Goods_Category" FOREIGN KEY ("ID_Cat") REFERENCES "Categories" (ID) ON DELETE SET NULL ON UPDATE CASCADE; |
То есть при удалении какой-либо категории из таблицы категорий,
товар, относящийся к этой категории, не будет удален, а
перейдет в положение NULL — то есть не относящийся ни к одной
из категорий.
И таких ситуаций (и более реальных) бывает достаточно много.
------------------------
Также, если все поля объявить как NOT NULL могут наступить
приличные тормоза при изменении/вставке данных, поскольку,
(если я правильно понимаю), при создании поля типа NOT NULL
создается триггер базы данных, который каждый раз срабатывает
при изменении значения поля, проверяя его.
То есть, сделав все поля NOT NULL, можете получить дополнительные
тормоза при вставке/изменении поля.
Так что советую прежде очень продумать, какие именно поля
должны быть NOT NULL, а к какие нет.
|
|
Nick |
Отправлено: 08.06.2004, 12:15 |
|
Машинист паровоза
Группа: Участник
Сообщений: 247
|
Ну в категории можно и 0 поставить
а то что условие
if ( kat1 <> kat2 ) // = false если любое из значений NULL
мне очень не пондравилось
пришлось делать функцию mnz (NULL) = 0
и очень во многих местах переделывать условия
типа
if ( (kat1 is null and kat2 is not null) or
(kat1 is not null and kat2 is null) or
(kat1 <> kat2))
вообше-то кажется это правильно на всех языках
в Access было тоже (не совсем уверен)
|
|
AVC |
Отправлено: 08.06.2004, 12:35 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
В большинстве СУБД есть специальная функция типа IsNull(arg1,arg2) возвращающая первый не Null аргумент.
Значение Null нужно, полезно и удобно если уметь с ним работать. |
|
Gedeon |
Отправлено: 08.06.2004, 12:53 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
QUOTE (AVC @ 08/06/2004, 13:37) | В большинстве СУБД есть специальная функция типа IsNull(arg1,arg2) возвращающая первый не Null аргумент.
Значение Null нужно, полезно и удобно если уметь с ним работать. |
Полностью за. Формируйте запросы с помощью таких функций как IsNull там где они Вам не нужны и проблем не будет. Считаю очень удобным например следующее
что-то + NULL = NULL
очень удобно для формирования отчетов.
|
|
Nick |
Отправлено: 08.06.2004, 13:59 |
|
Машинист паровоза
Группа: Участник
Сообщений: 247
|
Вот я хотел узнать у тех
кто с ним подружился
но так и не въеду
например
чем это замечательно замечательно в отчете
1 + NULL = NULL
^ ^ ^
колонка 1 колонка 2 итоговая колонка
разве это замечательно
ЗП допустим
AVC — 300$
Gedeon — 300$
Nick — нисколько не получил потому что никак не въедет (NULL)
итого ЗП = NULL
|
|
AVC |
Отправлено: 08.06.2004, 14:11 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
А для этого и есть
Итого = IsNull(AVC,0) + IsNull(Gedeon,0) + IsNull(Nik,0) -> 600
Кстати агрегатные функции работают с сумированием правильно.
А, например для number, как вы будете отличать в каких полях есть данные но они равны 0 а в каких их просто нет без Null.
|
|
Nick |
Отправлено: 08.06.2004, 16:24 |
|
Машинист паровоза
Группа: Участник
Сообщений: 247
|
isnull нет в IBase, FireBird попробовал нет
я пользуюсь своей UDF
вернее двумя mnz(:value_Int) и mnzf(:value_dbl)
Ладно, давайте закроем это дело.
Я открыл его когда, в очередной раз наткнулся
на сравнение
if ( param1 <> param2 )
когда начинал делать базу, забыл про это дело
|
|
Deem |
Отправлено: 09.06.2004, 09:39 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
QUOTE (Gedeon @ 08/06/2004, 13:55) | [QUOTE=AVC,08/06/2004, 13:37] Считаю очень удобным например следующее
что-то + NULL = NULL
очень удобно для формирования отчетов. |
Ага.... Например, при NAME || NAME2 || SURNAME (грубо говоря) для получения имени одним полем не дай бог отчество (NAME2) не указано.
А вобще и я не вьехал в одну весчь: при объединении двух таблиц если в одной из них нет соответствующей записи, то запись первой тоже отпадает. Я извращался по всякому, но оптимального решения не нашел. Хотя знаю , что оно есть.
к примеру (очень примерно):
STUFFS: NAME, ID
SERVICES: SERVICE, DONE, STUFFID
Если обслуживане имеет DONE = 1, то указан спец. А если нет — то NULL.
При выборке
SELECT SERVICE, DONE, NAME FROM STUFFS, SERVICES
WHERE STUFFID = ID
записи из SERVICES без STUFFID выпадают. Тут можно извратиться и ввести спеца 'не указан' c ID = 0, а у ID в STUFFS — умолчательное 0. Да и DONE тоже может пригодиться.
Но бывают и более заваороченные случаи. Раскройте мне глаза, пожалуйста.
|
|
AVC |
Отправлено: 09.06.2004, 11:45 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
QUOTE (Deem @ писал) |
при объединении двух таблиц если в одной из них нет соответствующей записи, то запись первой тоже отпадает
|
Это называется Inner join и используется для объединения по умолчанию. То что вас интересует обзывается термином outer join и может быть right и left. Языковая реализация (способ записи) внешних объединений зависит от сервера (или его настроек) СУБД. |
|
Gedeon |
Отправлено: 09.06.2004, 12:10 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
Еще хочу добавить, что в самом вопросе указания конкретной БД не было, спорить не буду, есть такие в которых NULL действительно проблема, но возмите SQLServer, Oracle (остальных не знаю вообще или очень поверхностно) там просто достаточно научиться им пользоваться и все.
|
|
AVC |
Отправлено: 09.06.2004, 12:32 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
По примерам Deem
SQL | Select SERVICE, DONE, NAME FROM STUFFS, SERVICES
From Stuff, Services
Where StuffID = ID
|
Это inner join
Результат — те записи из Stuff для которых есть записи в Services
SQL | Select SERVICE, DONE, NAME FROM STUFFS, SERVICES
From Stuff left outer join Services on (StuffID = ID)
|
Это left outer join
Результат — все записи из Stuff и записи из Services если они есть. Если в Services нет записей то поля заполнены Null'ами.
правое внешнее объединения аналогично левому.
SQL | Select SERVICE, DONE, NAME FROM STUFFS, SERVICES
From Stuff ,Services
|
Если память не изменяет это cross join
Полное объединение (декартово произведение) таблиц. Обычно результат ошибки. |
|
Deem |
Отправлено: 10.06.2004, 16:40 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Ну, значит я ламерюга. Сто раз ковырял этот JOIN, однако понял только, что используется для объединения аналогично where a = b.
Это же офигеть как круто! и просто. Спасибо.
|
|
Deem |
Отправлено: 11.06.2004, 10:58 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Просветите меня окончательно: как три таблы объединить при помощи JOIN? У меня записи размножаются, вроде как связываются только две из трех.
select name, service, ddate
From SPEC SP right join SERVICE SE on (SE.SPECID = SP.ID),
DATE DA right join SERVICE S on (S.ID = DA.SERVICEID)
Там не зпт, видимо, должна стоять.
Отредактировано Deem — 11/06/2004, 12:07
|
|
Deem |
Отправлено: 11.06.2004, 11:42 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Соре, разобрался:
From SPEC SP right join SERVICE SE on (SE.SPECID = SP.ID)
right join DATE DA on (SE.ID = DA.SERVICEID)
|
|
AVC |
Отправлено: 11.06.2004, 12:45 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
На всякий случай.
Синтаксис зависит от СУБД. Вот еще один интересный пример (Sybase):
Table A (Aid, A_Name)
1, a1
2, a2
3, a3
4, a4
Table B (Bid, B_Name, Aid)
1, b1, 1(a1)
2, b2, 2(a2)
3, b3, 1(a1)
4, b4, Null
Table C (Cid, C_Name, Aid, Bid)
1, c1, 2(a2), Null
2, c2, 1(a1), Null
3, c3, 1(a1), 2(b2)
4, c4, Null, 3(b3)
Связь A c B и C (бывший ваш вопрос)
Select A.A_Name, B.B_Name, C.C_Name
From
A left outer join B on (A.Aid = B.Aid)
,A left outer join C on (A.Aid = C.Aid)
результат
a1, b1, c2
a1, b1, c3
a1, b3, c2
a1, b3, c3
a2, b2, c1
a3, -, -
a4, -, -
Связь A c B и A с C через B
Select A.A_Name, B.B_Name, C.C_Name
From
A left outer join (B left outer join C on (B.Bid = C.Bid))
on (A.Aid = B.Aid)
результат
a1, b1 -
a1, b3, c4
a2, b2, c3
a3, -, -
a4, -, -
Отредактировано AVC — 11/06/2004, 13:53 |
|
Deem |
Отправлено: 14.06.2004, 11:08 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Вовово. Я такое пытался провеонуть, однако ошибался, видно, в сиснтаксисе.
Хороший пример.
|
|
|