Simplifique a construção em MATCH SIMPLE
comportamento das restrições fk
Se pelo menos uma coluna de restrição estrangeira de várias colunas com padrão
MATCH SIMPLE
comportamento é NULL
, a restrição não é aplicada. Você pode construir isso para simplificar amplamente seu design. CREATE SCHEMA test;
CREATE TABLE test.status(
status_id integer PRIMARY KEY
,sub bool NOT NULL DEFAULT FALSE -- TRUE .. *can* be sub-status
,UNIQUE (sub, status_id)
);
CREATE TABLE test.entity(
entity_id integer PRIMARY KEY
,status_id integer REFERENCES test.status -- can reference all statuses
,sub bool -- see examples below
,additional_col1 text -- should be NULL for main entities
,additional_col2 text -- should be NULL for main entities
,FOREIGN KEY (sub, status_id) REFERENCES test.status(sub, status_id)
MATCH SIMPLE ON UPDATE CASCADE -- optionally enforce sub-status
);
É muito barato para armazenar algumas colunas NULL adicionais (para entidades principais):
- Quanto espaço em disco é necessário para armazenar um valor NULL usando o banco de dados postgresql?
BTW, por documentação:
Dados de demonstração:
INSERT INTO test.status VALUES
(1, TRUE)
, (2, TRUE)
, (3, FALSE); -- not valid for sub-entities
INSERT INTO test.entity(entity_id, status_id, sub) VALUES
(11, 1, TRUE) -- sub-entity (can be main, UPDATES to status.sub cascaded)
, (13, 3, FALSE) -- entity (cannot be sub, UPDATES to status.sub cascaded)
, (14, 2, NULL) -- entity (can be sub, UPDATES to status.sub NOT cascaded)
, (15, 3, NULL) -- entity (cannot be sub, UPDATES to status.sub NOT cascaded)
SQL Fiddle (incluindo seus testes).
Alternativa com FK único
Outra opção seria inserir todas as combinações de
(status_id, sub)
no status
tabela (só pode haver 2 por status_id
) e tem apenas uma única restrição fk:CREATE TABLE test.status(
status_id integer
,sub bool DEFAULT FALSE
,PRIMARY KEY (status_id, sub)
);
CREATE TABLE test.entity(
entity_id integer PRIMARY KEY
,status_id integer NOT NULL -- cannot be NULL in this case
,sub bool NOT NULL -- cannot be NULL in this case
,additional_col1 text
,additional_col2 text
,FOREIGN KEY (status_id, sub) REFERENCES test.status
MATCH SIMPLE ON UPDATE CASCADE -- optionally enforce sub-status
);
INSERT INTO test.status VALUES
(1, TRUE) -- can be sub ...
(1, FALSE) -- ... and main
, (2, TRUE)
, (2, FALSE)
, (3, FALSE); -- only main
etc.
Respostas relacionadas:
- MATCH FULL vs MATCH SIMPLE
- Restrição de chave estrangeira de duas colunas somente quando a terceira coluna NÃO é NULL
- Validação de exclusividade no banco de dados quando a validação tem uma condição em outra tabela
Manter todas as tabelas
Se você precisar de todas as quatro tabelas por algum motivo que não esteja na pergunta, considere esta solução detalhada para uma pergunta muito semelhante no dba.SE:
Herança
... pode ser outra opção para o que você descreve. Se você pode viver com algumas grandes limitações . Resposta relacionada: