Crea un UNIQUE indice multicolonna su (product_id, variant_id) :
CREATE UNIQUE INDEX line_items_prod_var_idx ON line_items (product_id, variant_id);
Tuttavia, ciò consentirebbe più voci di (1, NULL) per (product_id, variant_id) perché NULL i valori non sono considerati identici.
Per compensare, creare inoltre un UNIQUE parziale indice su product_id :
CREATE UNIQUE INDEX line_items_prod_var_null_idx ON line_items (product_id)
WHERE variant_id IS NULL;
In questo modo puoi inserire (1,2) , (1,3) e (1, NULL) , ma nessuno dei due una seconda volta. Velocizza anche le query con condizioni su una o entrambe le colonne.
Risposta recente e correlata su dba.SE, applicabile quasi direttamente al tuo caso:
- vincolo univoco multicolonna PostgreSQL e valori NULL