Restrição de coluna exclusiva personalizada, aplicada apenas se uma coluna tiver um valor específico

19

É possível ter uma restrição de coluna exclusiva personalizada da seguinte maneira? Suponha que eu tenha duas colunas subsete typeambas as strings (embora os tipos de dados provavelmente não importem).

Se typefor "verdadeiro", quero que a combinação de typee subsetseja única. Caso contrário, não há restrições. Estou usando o PostgreSQL 8.4 no Debian.

Faheem Mitha
fonte

Respostas:

31

Em outras palavras, você quer subsetser único se type = 'true'.
Um índice exclusivo parcial fará isso:

CREATE UNIQUE INDEX tbl_some_name_idx ON tbl (subset) WHERE type = 'true';

Dessa forma, você pode até fazer combinações com NULLúnicas, o que não é possível de outra maneira - conforme detalhado nesta resposta relacionada:
Restrição exclusiva de várias colunas do PostgreSQL e valores NULL

Erwin Brandstetter
fonte
Obrigado Erwin. Não vi essa opção quando examinei a documentação. Um link mais direto é postgresql.org/docs/current/interactive/indexes-partial.html . Veja o Exemplo 11-3.
Faheem Mitha 23/03
@FaheemMitha: vinculei um nível mais alto, pois você precisa combinar um índice parcial com um índice exclusivo .
Erwin Brandstetter 23/03
11
@ Erwin Essa página (sobre índices parciais), tem um exemplo com índice exclusivo parcial.
ypercubeᵀᴹ
@ypercube: Ah, certo. Esse é o melhor link. Mudei minha resposta para apontar para o último capítulo.
Erwin Brandstetter 23/03
6

Isso é complementar à resposta de Erwin acima, mas o PostgreSQL suporta vários tipos de índices. Geralmente, estes não são mutuamente exclusivos. Você pode pensar neles como sendo:

  • Método de índice (btree, GiST, GIN, etc). Escolha um, se necessário (btree é o padrão)
  • Parcial ou completo. Se parcial, use uma cláusula where
  • Direto ou funcional. Você pode indexar a saída de funções.
  • Exclusivo ou não exclusivo

Tudo isso pode ser combinado de várias maneiras. Tudo o que você está fazendo aqui é usar os recursos exclusivos e parciais, o que fornece índices únicos parciais (que são extremamente úteis para você descobrir).

Mas suponha que você queira ter um índice que não diferencia maiúsculas de minúsculas no campo do subconjunto em que tipo é verdadeiro. Então você adicionaria uma definição funcional:

CREATE INDEX my_index_name_idx_u ON tbl (lower(subset)) WHERE type;

Observe que isso cria um índice exclusivo na saída da função lower () chamada no atributo de subconjunto em que type é true.

Chris Travers
fonte
Portanto, o índice na resposta de Erwin é direto, enquanto o índice do seu exemplo em funcional, correto?
Faheem Mitha 24/03
@FaheemMitha: Correto.
Erwin Brandstetter 24/03