PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Ajouter une contrainte pour rendre la colonne unique par groupe de lignes

Comme @lad2025 a commenté , status devrait vraiment être boolean . Moins cher, plus propre.

Dans tous les cas, vous pouvez imposer votre règle avec un index unique partiel :

Pour autoriser zéro ou une ligne avec status = 'Active' dans tout le tableau :

CREATE UNIQUE INDEX tbl_active_uni ON tbl (status)
WHERE status = 'Active';

Pour autoriser zéro ou une ligne avec status = 'Active' par userid , créez userid la colonne indexée :

CREATE UNIQUE INDEX tbl_userid_active_uni ON tbl (userid)
WHERE status = 'Active';

Notez que userid IS NULL ne déclencherait pas de violations uniques, car deux valeurs NULL ne sont jamais considérées comme égales. userid doit être set NOT NULL dans ce cas.

Pourquoi indexer et non contraindre ?

Répondre à votre question dans le commentaire  :Ceci est un index, pas une CONSTRAINT .

L'indice pour le premier cas est minuscule , contenant une ou aucune ligne.
L'index du second cas contient une ligne par userid existant , mais c'est le moyen le moins cher et le plus rapide , en plus d'être propre et sécuritaire. Vous auriez besoin d'un index pour vérifier les autres lignes dans tous les cas pour que cela soit rapide.

Vous ne pouvez pas avoir de CHECK vérification des contraintes sur les autres lignes - du moins pas de manière propre et fiable. Il y a des façons que je ne recommanderais certainement pas pour ce cas :

Si vous utilisez un UNIQUE contrainte sur (userid, status) (qui est également implémenté avec un index unique en arrière-plan !), vous ne pouvez pas le rendre partiel , et tous les combinaisons sont imposées pour être uniques. Vous pourriez utilisez toujours ceci si vous travaillez avec status IS NULL pour tous les cas sauf 'Active' Cas. Mais cela imposerait en fait un index beaucoup plus grand comprenant tous lignes.