É possível no PostgreSQL 9.6 aplicar uma restrição de chave estrangeira nos limites inferior e superior de um intervalo (de inteiros no meu caso)?
Atualmente, mantenho o limite inferior e o limite superior em duas colunas, mas gostaria de unificá-los em uma coluna de intervalo, mantendo as referências de chave estrangeira.
Exemplo
Eu tenho uma tabela contendo uma lista de sessões, algo como:
CREATE TABLE sessions (
session_id SERIAL PRIMARY KEY,
session_start TIMESTAMPTZ NOT NULL,
description TEXT
);
e, em seguida, uma tabela de grupos dessas sessões que atualmente é expressa como:
CREATE TABLE session_groups (
group_id SERIAL PRIMARY KEY,
first_session INTEGER NOT NULL UNIQUE,
last_session INTEGER NOT NULL UNIQUE,
description TEXT,
FOREIGN KEY (first_session)
REFERENCES sessions (session_id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
FOREIGN KEY (last_session)
REFERENCES sessions (session_id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
CONSTRAINT last_session_after_first
CHECK (last_session >= first_session)
);
O que eu gostaria:
CREATE TABLE session_groups (
group_id SERIAL PRIMARY KEY,
session_range INT4RANGE NOT NULL UNIQUE,
description TEXT,
FOREIGN KEY (lower(session_range))
REFERENCES sessions (session_id)
ON UPDATE CASCADE
ON DELETE RESTRICT,
FOREIGN KEY (upper(session_range))
REFERENCES sessions (session_id)
ON UPDATE CASCADE
ON DELETE RESTRICT
-- Dropped last_session_after_first constraint since
-- the INT4RANGE type checks it automatically.
);
que está lançando um erro de sintaxe.
Não é permitido ter expressões arbitrárias em
FOREIGN KEY
restrições, apenas colunas. É por isso que você obtém um erro ao tentar a segunda abordagem.No entanto, você pode usar a
VIEW
para acessar a tabela:Você pode até adicionar gatilhos e, em seguida, ser capaz de INSERT/UPDATE/DELETE da view, como se fosse uma tabela normal.
Notas laterais:
UNIQUE
restrições, em(first_session)
e(last_session)
, enquanto o 2º tem 1UNIQUE
restrição, em(first_session, last_session)
. Estes não são designs equivalentes, portanto, reexamine seus requisitos.'[)'
parâmetro padrão (inclusive-exclusivo) para aint4range
coluna. Você pode querer mudar isso para'[]'
(tudo incluído), dependendo de como você deseja salvar os intervalos.Exemplos:
int4range(1,1)
eint4range(1,1,'[)')
é o intervalo vazio enquantoint4range(1,1,'[]')
é o[1,2)
intervalo.Se você deseja impor / evitar intervalos sobrepostos, não precisa de uma
UNIQUE
restrição, mas de umaEXCLUDE
restrição:Consulte também a documentação sobre restrições em tipos de intervalo . Você provavelmente precisará adicionar a extensão também: