Домен - іменований тип на основі наявного, з обмеженнями. Правило описується один раз і використовується в багатьох колонках.
CREATE DOMAIN email AS text
CHECK (VALUE ~ '^[^@\s]+@[^@\s]+\.[^@\s]+$');
CREATE DOMAIN positive_money AS numeric(12, 2)
CHECK (VALUE >= 0);
CREATE DOMAIN country_code AS char(2)
CHECK (VALUE ~ '^[A-Z]{2}$');
CREATE TABLE customers (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
contact_email email NOT NULL,
billing_email email,
credit_limit positive_money NOT NULL DEFAULT 0,
country country_code NOT NULL
);
Переваги:
- Одне правило - скрізь однаково. Не буде таблиці, де email перевіряється інакше чи не перевіряється взагалі.
- Зміна в одному місці:
ALTER DOMAIN email ADD CONSTRAINT ...застосується до всіх колонок. - Самодокументування: тип колонки
positive_moneyпояснює більше, ніжnumeric(12, 2).
Обмеження й нюанси:
NOT NULLу домені працює неочевидно (наприклад, приLEFT JOINі в результатах функцій) - документація радить ставитиNOT NULLна колонку, а не в домен.- Зміна обмеження домену перевіряє всі колонки цього типу в усій базі - на великих таблицях довго. Як і з
CHECK, єNOT VALID+VALIDATE CONSTRAINT. - Підтримка ORM: Laravel-міграції не мають методу для доменів - колонку додають сирим SQL, а для застосунку це звичайний
textчиnumeric. - Перевірка email регулярним виразом у базі - лише базовий захист від сміття. Справжню валідацію (і повідомлення користувачу) робить застосунок; база гарантує, що навіть код в обхід валідації не запише явно некоректне значення.
Домени корисні в базах, куди пишуть кілька застосунків чи сервісів: правило живе там, де дані, а не в кожному з них окремо.