Составной первичный ключ применяет ограничения NOT NULL для вовлеченных столбцов
это одно странное, нежелательное поведение, с которым я столкнулся в Postgres: Когда я создаю таблицу Postgres с составными первичными ключами, она применяет ограничение NOT NULL для каждого столбца составной комбинации.
например,
CREATE TABLE distributors (m_id integer, x_id integer, PRIMARY KEY(m_id, x_id));
обеспечивает NOT NULL
ограничения на столбцы m_id
и x_id
, которого я не хочу!
MySQL этого не делает. Я думаю, что Oracle этого не делает.
Я понимаю, что PRIMARY KEY
обеспечивает UNIQUE
и NOT NULL
автоматически, но это имеет смысл для одного столбца первичного ключа. В таблице первичного ключа с несколькими столбцами уникальность определяется комбинацией.
есть ли простой способ избежать такого поведения Postgres?
Если я выполню это:
CREATE TABLE distributors (m_id integer, x_id integer);
Я не получаю никаких NOT NULL
ограничениями, конечно.
1 ответов
если вы нужно чтобы разрешить значения 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)
);
Примечание, однако (в документации):
для уникального ограничения значения null не считаются равными.
в вашей case, вы можете войти (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. Многоколоночный уникальный индекс для выражений
вместо уникальности. Нам нужно свободное значение по умолчанию, которое никогда не присутствует в задействованных столбцах, например -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))
как некоторые СУБД обрабатывают вещи не всегда является полезным индикатором правильного поведения. The руководство Postgres намекает на это:
это означает, что даже при наличии уникального ограничения можно для хранения повторяющихся строк, содержащих значение null, по крайней мере в одной из в Столбцах. Это поведение соответствует стандарту SQL, но!--17-->мы слышали, что другие базы данных SQL могут не следовать этому правилу. Так что будьте осторожны, когда разработка приложений, которые должны быть портативными.
жирным выделено мной.