Размещайте ограничения СНЕСК() табличного уровня в конце объявления таблицы
Обоснование
В SQL-продуктах эти ограничения поддерживаются не особенно широко, хотя и являются законной частью синтаксиса SQL-92. Их предикаты действуют на всю таблицу, а не на отдельные строки, что предполагает использование агрегирующих функций.
CREATE TABLE Prizes
(...
CONSTRAINT only_5_prizes_each_winner
CHECK (NOT EXISTS (SELECT *
FROM Prizes AS P1
GROUP BY P1.contestant_id HAVING COUNT(*) > 5
)
),
CONSTRAINT nojnissing_ticket_nbrs
CHECK ((SELECT MAX(ticket_nbr) - MIN(ticket_nbr) + 1
FROM Prizes AS P1)
= (SELECT COUNT(ticketjibr)
FROM Prizes AS P1)
);
Исключения
Нет.
Используйте для многотабличных ограничений выражение CREATE ASSERTION
Обоснование
В SQL-продуктах эти ограничения поддерживаются не особенно широко, хотя и являются законной частью синтаксиса SQL-92. Их предикаты действуют не на одну, а сразу на несколько таблиц. Это означает, что и описываться они должны на более высоком уровне. Размещайте многотабличные ограничения СНЕСК() в выражениях CREATE ASSERTION, а не в описаниях таблиц. С практической точки зрения, все ограничения, примененные к пустой таблице, должны возвращать значение TRUE. Выражение CREATE ASSERTION позволяет задавать такое поведение. Имя утверждения ведет себя так же, как имя ограничения.
CREATE ASSERTION enough_money_to_pay_prizes
AS
CHECK ((SELECT SUM(pnze_money)
FROM Prizes AS P1)
<= (SELECT SUM(cash_on_hand)
FROM Bank));
Исключения
Если ваш SQL-продукт не поддерживает выражение CREATE ASSERTION, ничего, конечно, нельзя поделать. Если же оно поддерживается, для нарушения данного правила должно быть очень серьезное основание, связанное с дизайном схемы.
Используйте для каждой проверки собственное ограничение СНЕСК()
Обоснование
Создавайте несколько простых ограничений CHECK() с собственной конструкцией для каждого, вместо написания одного сложного ограничения со множеством тестов.
Имя, присвоенное ограничению, отображается в сообщении об ошибке, когда ограничение нарушено. Если все проверки проводятся в рамках единой конструкции CHECK(), какое имя ей дать? Представьте себе, что в одном ограничении вы одним махом проверяете правильное использование прописных букв, пробелов и длину строки почтового адреса. Можно, конечно, присвоить этому ограничению имя наподобие “ошибочный адрес” и надеяться, что пользователь сам сообразит, что сделал неправильно. Но гораздо лучше будет организовать отдельные проверки, тем самым дав пользователю более конкретное указание на ошибку.
Исключения
Если ваш SQL-продукт поддерживает предикат SIMILAR TO (схожий с функцией grep из стандарта POSIX), иногда оказывается удобным создание длинных регулярных выражений.
Возможно, вы захотите создать составное ограничение с невнятным именем из соображений безопасности, но мне такую ситуацию представить довольно трудно.
Если у таблицы нет ключа, это не таблица
Обоснование
Здесь мы подбираемся к самой сути таблицы. Беда в том, что многие новички вообще не понимают, что такое ключ. Ключ должен состоять из подмножества атрибутов (столбцов) таблицы. Нет и не может быть универсального “безразмерного” ключа. Поскольку не существует двух одинаковых наборов сущностей, уникальные атрибуты для них должны подбираться на индивидуальной основе. Господь, к несчастью, не присвоил каждой созданной им вещи 17-буквенный код на иврите.
В табл. 3.1 приводится классификация ключей.
Табл. 3.1. Типы ключей
Естественный ключ | Искусственный ключ | Явный физический указатель | Системный суррогатный ключ | |
Строится по реальной модели данных | Да | Нет | Нет | Нет |
Проверяем по реальной модели | Да | Нет, исходит из надежного источника | Нет | Нет |
Проверяем сам по себе | Да | Да, например, по синтаксису, по контрольному разряду | Нет | Нет |
Переносим на другую платформу | Да | Да | Нет | Нет |
Доступен пользователю | Да | Да | Да | Нет, может быть изменен системой |
1. Естественный ключпредставляет собой набор атрибутов из таблицы и действует как уникальный идентификатор. Он виден пользователю.Его можно проверить на корректность как по реальной модели данных,так и сам по себе. Пример, универсальный код продукта UPC можно прочитать на упаковке, проверить сканером, сравнить с данными на Web-узле производителя.
2. Искусственный ключпредставляет собой дополнительный атрибут, специально введенный в таблицу для использования в качестве ключа. Он виден пользователю, не связан напрямую с реальной моделью данных, но может быть проверен сам по себе — по синтаксису, по контрольному разряду. Пример: свободные коды из схемы UPC, которые пользователь может присвоить своему продукту. Корректность кодов можно проверять только в пределах вашей организации. Если вы занимаетесь разработкой ключа самостоятельно, помните, что эго дело не из легких. Подробнее об этом — в главе 5.
3. Явный физический указательне основан на модели данных и доступен пользователю. Предсказать или проверить его значение нельзя. Система вычисляет его, основываясь на физическом хранении данных. Пример: поля IDENTITY в семействе T-SQL, другие нестандартные нереляционные средства автонумерации, указатели, основанные на номерах цилиндра и дорожки жесткого диска в Oracle. Технически, это вообще не ключи, так как к логической модели данных они не имеют никакого отношения. Удобны для ленивых, не желающих думать программистов-“чайников”. Наихудший способ программирования на SQL
4. Системный суррогатный ключгенерируется системой для замещения реального ключа на основе атрибутов из таблицы; пользователю недоступен. Пример: алгоритмы хэширования Teradata. Определяющее значение имеет тот факт, что пользователь ни при каких обстоятельствах не видит суррогатный ключ, не может использовать его в командах DELETE и UPDATE или создать командой INSERT. Если бы он мог это сделать, то немедленно повредил бы целостность данных, нарушив соответствие между реальными и суррогатными ключами. Суррогатные ключи поддерживаются системой.
Обратите внимание, что суррогатные ключи иногда путают с физическими указателями; на самом же деле они концептуально различны.