J'ai une table comme celle-ci:
create table my_table (
id int8 not null,
id_A int8 not null,
id_B int8 not null,
id_C int8 null,
constraint pk_my_table primary key (id),
constraint u_constrainte unique (id_A, id_B, id_C)
);
Et je veux (id_A, id_B, id_C)
être distinct dans n'importe quelle situation. Donc, les deux insertions suivantes doivent entraîner une erreur:
INSERT INTO my_table VALUES (1, 1, 2, NULL);
INSERT INTO my_table VALUES (2, 1, 2, NULL);
Mais il ne se comporte pas comme prévu car, selon la documentation, deux NULL
valeurs ne sont pas comparées, de sorte que les deux insertions passent sans erreur.
Comment puis-je garantir ma contrainte unique même si cela id_C
peut être le NULL
cas? En réalité, la vraie question est la suivante: puis-je garantir ce type d'unicité dans "pure sql" ou dois-je l'implémenter à un niveau supérieur (java dans mon cas)?
postgresql
constraint
null
unique-constraint
Manuel Leduc
la source
la source
(1,2,1)
et(1,2,2)
dans les(A,B,C)
colonnes. Faut-(1,2,NULL)
il permettre l'ajout ou non d'un?Réponses:
Vous pouvez le faire en SQL pur . Créez un index unique partiel en plus de celui que vous avez:
De cette façon, vous pouvez entrer
(a, b, c)
dans votre tableau:Mais rien de tout cela une seconde fois.
Ou utilisez deux
UNIQUE
index partiels et aucun index complet (ou contrainte). La meilleure solution dépend des détails de vos besoins. Comparer:Bien que cela soit élégant et efficace pour une seule colonne nullable dans l'
UNIQUE
index, cela devient rapidement incontrôlable pour plus. Discuter de cela - et comment utiliser UPSERT avec des index partiels:À part
Aucune utilisation pour les identificateurs de casse mixtes sans guillemets doubles dans PostgreSQL.
Vous pouvez considérer une
serial
colonne comme clé primaire ou uneIDENTITY
colonne dans Postgres 10 ou version ultérieure. Apparenté, relié, connexe:Alors:
Si vous ne prévoyez pas plus de 2 milliards de lignes (> 2147483647) pendant la durée de vie de votre table (y compris les lignes inutilisées et supprimées), envisagez
integer
(4 octets) au lieu debigint
(8 octets).la source
J'ai eu le même problème et j'ai trouvé un autre moyen d'avoir un NULL unique dans la table.
Dans mon cas, le champ
foreign_key_field
est un entier positif et ne sera jamais -1.Donc, pour répondre à Manuel Leduc, une autre solution pourrait être
Je suppose que les identifiants ne seront pas -1.
Quel est l'avantage de créer un index partiel?
Dans le cas où vous ne disposez pas de la clause NOT NULL,
id_a
,id_b
etid_c
peut être NULL ensemble qu'une seule fois.Avec un index partiel, les 3 champs peuvent être NULL plusieurs fois.
la source
COALESCE
peut être efficace pour limiter les doublons, mais l'index ne serait pas très utile pour interroger car c'est un index d'expression qui ne correspond probablement pas aux expressions de requête. C'est-à-dire, à moins queSELECT COALESCE(col, -1) ...
vous ne frappiez pas l'index.Une valeur Null peut signifier que la valeur n'est pas connue pour cette ligne pour le moment mais qu'elle sera ajoutée ultérieurement, si elle est connue (exemple
FinishDate
pour une exécutionProject
) ou qu'aucune valeur ne peut être appliquée pour cette ligne (exempleEscapeVelocity
pour un trou noirStar
).À mon avis, il est généralement préférable de normaliser les tables en éliminant toutes les valeurs nulles.
Dans votre cas, vous souhaitez autoriser
NULLs
votre colonne, mais vous ne souhaitezNULL
autoriser qu’une seule de ces colonnes . Pourquoi? Quel genre de relation est-ce entre les deux tables?Peut-être que vous pouvez simplement changer la colonne
NOT NULL
et stocker, au lieu deNULL
, une valeur spéciale (comme-1
) connue pour ne jamais apparaître. Cela résoudra le problème de la contrainte d'unicité (mais peut avoir d'autres effets secondaires éventuellement indésirables. Par exemple, utiliser-1
pour signifier "inconnu / ne s'applique pas" faussera toute somme ou tout calcul moyen de la colonne. Ou tous ces calculs devront prendre en tenant compte de la valeur spéciale et l'ignorer.)la source