Crie dois índices parciais :
CREATE UNIQUE INDEX favo_3col_uni_idx ON favorites (user_id, menu_id, recipe_id)
WHERE menu_id IS NOT NULL;
CREATE UNIQUE INDEX favo_2col_uni_idx ON favorites (user_id, recipe_id)
WHERE menu_id IS NULL;
Dessa forma, só pode haver uma combinação de
(user_id, recipe_id)
onde menu_id IS NULL
, implementando efetivamente a restrição desejada. Possíveis desvantagens:
- Você não pode ter uma chave estrangeira referenciando
(user_id, menu_id, recipe_id)
. (Parece improvável que você queira uma referência FK com três colunas de largura - use a coluna PK!) - Você não pode basear
CLUSTER
em um índice parcial. - Consultas sem um
WHERE
correspondente condição não pode usar o índice parcial.
Se você precisa de um completo index, você pode, alternativamente, soltar o
WHERE
condição de favo_3col_uni_idx
e seus requisitos ainda são aplicados.O índice, agora compreendendo toda a tabela, se sobrepõe ao outro e fica maior. Dependendo das consultas típicas e da porcentagem de
NULL
valores, isso pode ou não ser útil. Em situações extremas, pode até ajudar a manter os três índices (os dois parciais e um total no topo). Esta é uma boa solução para uma coluna anulável única , talvez para dois. Mas fica fora de controle rapidamente para mais, pois você precisa de um índice parcial separado para cada combinação de colunas anuláveis, para que o número cresça binomialmente. Para várias colunas anuláveis , veja em vez disso:
- Por que minha restrição UNIQUE não é acionada?
A parte:aconselho não usar identificadores de maiúsculas e minúsculas no PostgreSQL.