PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Validação de exclusividade no banco de dados quando a validação tem uma condição em outra tabela


Infelizmente, não há solução tão simples e limpa quanto para sua pergunta anterior .

Isso deve fazer o trabalho:

  • Adicione um sinalizador redundante is_published para o Child tabela
    ALTER TABLE child ADD column is_published boolean NOT NULL;
    

    Torne-o DEFAULT FALSE ou o que você normalmente tem nas colunas pai ao inserir.
    Precisa ser NOT NULL para evitar uma brecha com NULL valores e padrão MATCH SIMPLE comportamento em chaves estrangeiras:
    Restrição de chave estrangeira de duas colunas somente quando a terceira coluna NÃO é NULL

  • Adicione uma restrição exclusiva (aparentemente inútil, mas) em parent(parent_id, is_published)
    ALTER TABLE parent ADD CONSTRAINT parent_fk_uni
    UNIQUE (parent_id, is_published);
    

    Desde parent_id é a chave primária, a combinação seria única de qualquer maneira. Mas isso é necessário para a seguinte restrição fk.

  • Em vez de referenciar parent(parent_id) com uma simples restrição de chave estrangeira , crie uma chave estrangeira de várias colunas em (parent_id, is_published) com ON UPDATE CASCADE .
    Dessa forma, o estado de child.is_published é mantido e aplicado pelo sistema de forma automática e mais confiável do que você poderia implementar com gatilhos personalizados:
    ALTER TABLE child
    ADD CONSTRAINT child_special_fkey FOREIGN KEY (parent_id, is_published)
    REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE;
    

  • Em seguida, adicione um índice ÚNICO parcial como na sua resposta anterior.
    CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
    WHERE is_published;
    

Claro, ao inserir linhas no child tabela você é forçado a usar o estado atual de parent.is_published agora. Mas esse é o ponto:reforçar a integridade referencial.

Esquema completo


Ou, em vez de adaptar um esquema existente, aqui está o layout completo:
CREATE TABLE parent(
    parent_id serial PRIMARY KEY
  , is_published bool NOT NULL DEFAULT FALSE
--, more columns ...
  , UNIQUE (parent_id, is_published)   -- required for fk
);

CREATE TABLE child (
    child_id serial PRIMARY KEY
  , parent_id integer NOT NULL
  , is_published bool NOT NULL DEFAULT FALSE
  , txt text
  , FOREIGN KEY (parent_id, is_published)
      REFERENCES parent (parent_id, is_published) ON UPDATE CASCADE
);

CREATE UNIQUE INDEX child_txt_is_published_idx ON child (text)
WHERE is_published;