Ако трябва за да разрешите NULL стойности, използвайте UNIQUE
ограничение вместо PRIMARY KEY
(и добавете заместваща PK колона, предлагам serial
). Това позволява колоните да бъдат NULL:
CREATE TABLE distributor (
distributor_id serial PRIMARY KEY
, m_id integer
, x_id integer
, UNIQUE(m_id, x_id)
);
Забележка , обаче (по документация):
За целите на уникално ограничение нулевите стойности не се считат за равни.
Във вашия случай можете да въведете нещо като (1, NULL)
за (m_id, x_id)
произволен брой пъти, без да се нарушава ограничението. Postgres никога не счита две NULL стойности равни - според дефиницията в стандарта SQL.
Ако трябва да третирате NULL
стойности като равни за забрана на такива "дубликати", виждам две опции :
1. Два частични индекса
В допълнение към UNIQUE
ограничение по-горе:
CREATE UNIQUE INDEX dist_m_uni_idx ON distributor (m_id) WHERE x_id IS NULL;
CREATE UNIQUE INDEX dist_x_uni_idx ON distributor (x_id) WHERE m_id IS NULL;
Но това бързо излиза извън ръцете с повече от две колони, които могат да бъдат NULL. Вижте:
- Създайте уникално ограничение с нулеви колони
2. UNIQUE
с няколко колони индекс на изрази
Вместо ограничението UNIQUE. Нуждаем се от безплатна стойност по подразбиране, която никога не присъства в участващите колони, като -1
. Добавете CHECK
ограничения, за да го забраните:
CREATE TABLE distributor (
distributor serial PRIMARY KEY
, m_id integer
, x_id integer
, CHECK (m_id <> -1)
, CHECK (x_id <> -1)
);
CREATE UNIQUE INDEX distributor_uni_idx ON distributor (COALESCE(m_id, -1)
, COALESCE(x_id, -1))
Как определени RDBMS се справят с нещата не винаги е полезен индикатор за правилно поведение. Ръководството на Postgres намеква за това:
Това означава, че дори при наличието на уникално ограничение е възможно да се съхраняват дублиращи се редове, които съдържат нулева стойност в поне една от ограничените колони. Това поведение отговаря на стандарта SQL, но чухме, че други SQL бази данни може да не следват това правило .Така че бъдете внимателни, когато разработвате приложения, които са предназначени да бъдат преносими.
Удебелен акцент мой.