
Ограничения целостности
Как уже говорилось, типы данных — это один из способов ограничивать данные, которые могут быть сохранены в таблицы. Однако, для многих приложений, такое ограничение является слишком грубым. Например, колонка содержащая цену товара должна хранить только положительные числа. Но стандартного типа данных, который бы допускал только положительные числа не существует. В других случаях, вам может понадобится ограничить данные в колонке в соответствии с значениями других колонок или строк. Например, в таблице, содержащей информацию о товарах должна быть только одна строка для каждого товара.
Чтобы разрешить вышеописанные ситуации, SQL позволяет вам определять ограничения для колонок и таблиц. Ограничения дают вам настолько глубокий контроль над данными в ваших таблицах, насколько вы захотите. Если пользователь пытается сохранить в какой-либо колонке данные, которые попадают под ограничение, возникнет ошибка. Она возникнет даже если сохраняемое значение является значением по умолчанию.
Ограничения Check
Ограничение целостности check является наиболее часто используемым видом ограничения. Оно позволяет задать для определённой колонки, выражение, которое будет осуществлять проверку, помещаемого в эту колонку значения. Если значение удовлетворяет, заданному ограничению, то выражение должно возвращать Логическое значение (истина). Например, если требуется, чтобы в колонке были только положительные цены товаров, вы можете использовать:
CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0)
);
Как видите, определение ограничения следует после указания типа данных, как и определение значения по умолчанию. Значения по умолчанию и ограничения могут следовать в произвольном порядке. Ограничение check состоит из ключевого слова CHECK, за которым следует выражение в круглых скобках. Выражение в ограничении check должно использовать ту колонку, на которую оно накладывается, в противном случае это ограничение не будет иметь смысла.
Вы можете дать ограничению конкретное имя. Это сделает более понятными сообщения об ошибках и позволит вам ссылаться на это ограничение, когда вам понадобится его изменить. Синтакис такой:
CREATE TABLE products (
product_no integer,
name text,
price numeric CONSTRAINT positive_price CHECK (price > 0)
);
Таким образом, для создания именованого ограничения, используйте ключевое слово CONSTRAINT, за которым следует индентификатор (имя), после которого следует, собственно, определение ограничения. (Если при использовании этого синтаксиса вы не укажете имя ограничения, СУБД выберет имя за вас.)
Ограничение check может также накладываться на несколько колонок. Допустим, что вы храните обычную цену и цену со скидкой и хотите иметь уверенность в том, что цена со скидкой меньше, чем обычная цена.
CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0),
discounted_price numeric CHECK (discounted_price > 0),
CHECK (price > discounted_price)
);
Первые два ограничения нам уже знакомы. Третье использует новый синтаксис. Оно не привязано к определённой колонке, а появляется как отдельный элемент в списке колонок, разделённых запятой. Определения колонок и такие определения ограничений могут следовать в смешанном порядке.
Мы говорим, что первые два ограничения являются ограничениями на колоноки, в то время как третье является ограничением на таблицу, потому что оно пишется отдельно от определений колонок. Ограничения на колоноки могут таже быть записаны как ограничения на таблицу, в то время как обратное невсегда возможно, поскольку ограничение на колонку ссылается только на ту колонку, на которую оно накладывается. (PostgreSQL не заставляет следовать этому правилу, но вы должны следовать ему, если хотите, чтобы ваши определения таблиц работали в других СУБД). Рассмотренный выше пример может быть записан и так:
CREATE TABLE products (
product_no integer,
name text,
price numeric,
CHECK (price > 0),
discounted_price numeric,
CHECK (discounted_price > 0),
CHECK (price > discounted_price)
);
или даже так:
CREATE TABLE products (
product_no integer,
name text,
price numeric CHECK (price > 0),
discounted_price numeric,
CHECK (discounted_price > 0 AND price > discounted_price)
);
Выбор способа записи — это дело вашего вкуса.
Имена ограничениям на таблицу можно назначать таким же образом, как и ограничениям на колонки:
CREATE TABLE products (
product_no integer,
name text,
price numeric,
CHECK (price > 0),
discounted_price numeric,
CHECK (discounted_price > 0),
CONSTRAINT valid_discount CHECK (price > discounted_price)
);
Необходимо заметить, что ограничение check удовлетворяется, если выражение, указанное в ограничении возвращает значение истина или null. Поскольку большинство выражений возвращает значение null, если любой из операндов имеет значение null, то использование выражений не предотвратит появление значений null в колонках, на которые наложены ограничения. Чтобы иметь уверенность в том, что колонка не будет содержать значений null, можно использовать ограничение не-null, которое описывается в следующей секции.