Crea due indici parziali :
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;
In questo modo, può esserci solo una combinazione di (user_id, recipe_id)
dove menu_id IS NULL
, implementando efficacemente il vincolo desiderato.
Possibili inconvenienti:
- Non puoi avere una chiave esterna che faccia riferimento a
(user_id, menu_id, recipe_id)
. (Sembra improbabile che tu voglia un riferimento FK largo tre colonne:usa invece la colonna PK!) - Non puoi basare
CLUSTER
su un indice parziale. - Query senza un
WHERE
corrispondente condizione non può utilizzare l'indice parziale.
Se hai bisogno di un completo index, in alternativa puoi rilasciare il WHERE
condizione da favo_3col_uni_idx
e i tuoi requisiti sono ancora applicati.
L'indice, che ora comprende l'intera tabella, si sovrappone all'altra e diventa più grande. A seconda delle query tipiche e della percentuale di NULL
valori, questo può essere utile o meno. In situazioni estreme può anche aiutare a mantenere tutti e tre gli indici (i due parziali e un totale in alto).
Questa è una buona soluzione per una colonna nullable singola , forse per due. Ma sfugge rapidamente di mano per di più poiché è necessario un indice parziale separato per ogni combinazione di colonne nullable, quindi il numero cresce in modo binomiale. Per più colonne annullabili , vedi invece:
- Perché il mio vincolo UNIQUE non si attiva?
A parte:consiglio di non utilizzare identificatori di casi misti in PostgreSQL.