[SQL] Об использование NULL
Коллеги на работе делают недовольное лицо, когда я показываю такую структуру таблиц.ну это не разговор
что конкретно они говорят? что им не нравится?
Хотя я тоже бы скривился: NULL обычно обозначает неизвестно, а не нет.
На вскидку возникает несколько вопросов:
1. Насколько часто происходят продажи без скидочной карты? Т.е. так ли оправдан вынос в отдельную таблицу.
2. Как в такой системе вы собираетесь обеспечивать целостность? Даже с банальными внешними ключами придётся изгаляться: либо сначала вносить данные о размере скидки (что маразм либо отключать их проверку до commit.
3. Не окажется так что на одну покупку будут накладываться несколько скидок: скажем сезонная распродажа + карта клиента + бонус первым ста покупателям и вам захочется получить детали как получилась та скидка, которая получилась.
2. Информацию о скидке предоставляет сторонняя система типа "черный ящик". У нее один вход для карты, а на выходе - информация о скидке (сроке действия и т.д.). В моей базе данных списка карт нет.
3. Нет
ну это не разговорНичего конретно сказать не могут.
что конкретно они говорят? что им не нравится?
2. Информацию о скидке предоставляет сторонняя система типа "черный ящик". У нее один вход для карты, а на выходе - информация о скидке (сроке действия и т.д.). В моей базе данных списка карт нет.Мы о чём-то разном. Мне лень разбираться, но если ты уверен что не поимеешь проблем с внесением данных в базу, то, наверно, так оно и есть.
По основному вопросу: если в вышей системе не возможен вариант когда будет неизвестно была покупка со скидкой или нет, то ничего криминального в твоём дизайне нет.
Если твоим коллегам кажется что запросы по такой схеме писать сложнее сделай им представление с дополнительным столбцом
case
when DiscountSaleID is null then 0
else 1
end isDiscount
писать запросы будет легче, а производительность не пострадает.
Единственно что в этом варианте плохо — невозможность повесить битмап индекс для быстрого выделения только покупок со скидкой.
Ещё вопрос вдогонку: у тебя что за система? OLTP? DWH?
ну тойсть в табличку продаж ничего не добавлять
а в табличке скидок айдишник держать такой-же как у продажи
так как скидок мало (90% без них) то запросы вида
SELECT * FROM sales s
WHERE
NOT EXIST (SELECT * FROM discount_sales ds WHERE ds.id = s.id)
будут довольно быстрые
в основной же базе не будет лишнего столбца который обычно NULL
большинство запросов скорее всего даже джойнить вторую таблицу не будут
добавление сущности в два этапа: добавляем продажу, добавляем скидку к продаже
я бы скорее в таком случае делал связь 1 .. 1То что ты описал это не связь один-к-одному а супертип-подтип.
А один к одному реализуется либо одной, либо двумя ссылками.
То что ты описал это не связь один-к-одному а супертип-подтип.ну извините
я в терминологии не силен
В твоём случае, как уже сказали, Sales зависят от DiscountSales, твоя схема является говном уже хотя бы по этой причине.
select * from table where id is nullВСЕГДА будет делать full table scan (в оракле, по крайней мере). Полный просмотр таблицы на больших объемах будет тормозить. Да и вообще, full table scan - не есть гуд.
2) если используешь null-ы, то готовься обходить подводные камни трехзначной логики, когда ответ на вопрос 'а равно б' может иметь три варианта ответа 1) да, 2) нет, 3) null.
Вылезают всякие приколы со сравнениями и операциями над множествами (подзапрос и аналогичное по смыслу выражение с консрукцией exist даст разные результаты, если в подзапрос или exist попадают NULL-ы)
3) заведи специальное значение (и вообще, сделай столбец обязательным для заполнения. не хрен место в базе экономить с помощью NULL-ов - много не сэкономишь, а геммора от них можно поиметь.
ВСЕГДА будет делать full table scanневерное утверждение, особенно без указания какая база и какая версия подразумевается в утверждении.
1) null-ы не индексируются, так что если у тебя в столбце будет хотя бы один не NULL,то запросВо-первых, в поставленной задаче этот запрос должен возвращать 90% таблицы, так что full scan — это правильно.
code:select * from table where id is null
ВСЕГДА будет делать full table scan
Во-вторых, индексы бывают разные, некоторые — индексируют.
2) если используешь null-ы, то готовься обходить подводные камни трехзначной логики, когда ответ на вопрос 'а равно б' может иметь три варианта ответа 1) да, 2) нет, 3) null.И если не используешь null-ы всё равно нужно учитывать трёхзначную логику, т.к. то что ты её не используешь ещё не значит что СУБД её не использует.
Вылезают всякие приколы со сравнениями и операциями над множествами (подзапрос и аналогичное по смыслу выражение с консрукцией exist даст разные результаты, если в подзапрос или exist попадают NULL-ы)
3) заведи специальное значение (и вообще, сделай столбец обязательным для заполнения. не хрен место в базе экономить с помощью NULL-ов - много не сэкономишь, а геммора от них можно поиметь.Решение в целом ничем не лучше, решает только одну проблему: программистам вместо is null нужно будет писать != 'Спец значение'.
заведи специальное значение (и вообще, сделай столбец обязательным для заполнения. не хрен место в базе экономить с помощью NULL-овМсье не слышал о такой вещи, как foreign key?
Топикстартер предложил говнорешение; ты же предлагаешь в это говно ещё и костылей напихать. Может быть, лучше сразу сделать нормально?
Мсье не слышал о такой вещи, как foreign key?Ну это обходится: для фиктивного значения заводится запись с этим специальным значением в целевой таблице. Но это конечно очередной костыль.
Но это конечно очередной костыль.Вот и я про это.
Кроме того, тогда тебе ещё придётся городить очередной костыль вместо стандартного UNIQUE - ты же не хочешь, чтобы у двух разных Sale был один и тот же DiscountSale, если это не фиктивное значение?
Оставить комментарий
Corrector
Есть таблица продаж Sales. Часть продаж проходит при использовании скидочных карт. В этом случае необходимо записывать в БД некоторые поля, которые относятся к продаже с использованием скидки (например, процент фактической скидки и др.).Поскольку не все продажи идут со скидочными картами, нет необходимости записывать все эти поля в таблицу Sales. Для этого можно создать новую таблицу DiscountSales, и в таблице Sales сделать ссылку по ключевому полю DiscountSaleID. Если продажа происходит без использовании скидочных карт, то Sales.DiscountSaleID=NULL.
Получается, что факт продажи со скидочной картой или без нее определяется по значению поля Sales.DiscountSaleID (NOT NULL/NULL).
Коллеги на работе делают недовольное лицо, когда я показываю такую структуру таблиц.
Предполагается, что по таблице Sales будут делаться хитрожопые отчеты и, соответственно, запросы к БД. Однако, никаких препятствий при использовании NULL в качестве специального значения я не вижу.
Итак, можно ли так делать?