L'utilisation de plusieurs contraintes uniques sur une même table est-elle considérée comme une mauvaise conception?

8

Je regardais la INSERT INTO .. ON CONFLICT (..) DO UPDATE ..syntaxe de PostgreSQL et j'ai réalisé que vous ne pouvez pas faire plusieurs vérifications de contraintes uniques avec elle. Je veux dire, soit vous faites référence à un index unique composite par les noms de colonne ON CONFLICT (Name, Symbol)(si l'index unique est défini pour ces deux colonnes), soit vous utilisez la clé primaire. Si vous définissez deux index uniques distincts pour les colonnes, vous ne pouvez en rechercher qu'un.

CREATE TABLE student
    (Id int primary key, Name varchar(50), Symbol varchar(50),
      CONSTRAINT col1_unique UNIQUE (Name),
      CONSTRAINT col2_unique UNIQUE (Symbol)
    ); 

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (1, 'John', 'J'),
    (2, 'David', 'D'),
    (3, 'Will', 'W');

INSERT INTO student
    (Id, Name, Symbol)
VALUES
    (4, 'Jeremy', 'J')
   on conflict(Name) DO UPDATE
   set Name = 'Jeremy';

Pourrait générer une erreur en disant qu'il Js'agit d'un doublon. Cependant, cet exemple est tout simplement une mauvaise conception, car le symbole doit être dans une autre table et être connecté à la table des étudiants via une relation un à plusieurs. C'est pourquoi je me demande, peut-être que PostgreSQL a on conflictété conçu de cette façon, car vous pouvez TOUJOURS restructurer les tables d'une manière, où il n'y a qu'un seul index unique. Est-ce vrai ou il y a une autre raison?

Exemple de violon: http://www.sqlfiddle.com/#!17/9c0ce

appl3r
la source
vous pouvez TOUJOURS restructurer les tables d'une manière, où il n'y a qu'un seul index unique Il y a EntityA et EntityB. Il y a 2 instances de chacun. N'importe quelle instance EntityA peut se combiner avec n'importe quelle instance EntityB, il y a donc 2 combinaisons possibles où toutes les instances sont utilisées. Une de ces combinaisons est réalisée et vous devez la stocker. Essayez maintenant de créer un schéma où aucune table avec 2 uniques n'existe avec toutes les contraintes, ce qui empêche les données illégales.
Akina
@ Akina J'ai raté votre point. Si deux entités sont connectées via une relation plusieurs à plusieurs, vous créez une table de liens, stockant leurs clés étrangères, il n'y a donc pas de table avec 2 index uniques.
appl3r
Une instance ne peut être utilisée qu'une seule fois, vous devez donc avoir 2 indices uniqie dans une table liée (par chaque entité séparément) pour empêcher l'utilisation de l'instance déjà utilisée.
Akina
Bien que cela soit vrai, c'est un problème: voyez l'exemple dans la réponse de Michael Green. Diviser une table aussi simple en 4 tables est définitivement un casse-tête, car comme c'est un simple dictionnaire, ce n'est pas comme si vous aviez besoin de l'option "ON CONFLICT".
Walfrat

Réponses:

8

Il y a toujours la sixième forme normale ou clé de domaine. Ici, chaque colonne non clé devient sa propre table. Ainsi, la table 3NF T (Clé, Col1, Col2, ..) devient T1 (Clé, Col1), T2 (Clé, Col2) etc. Ces nouvelles tables qui nécessitent l'unicité peuvent la faire déclarer.

Je pense cependant qu'avoir plusieurs contraintes uniques sur une table est parfaitement OK. Prenons par exemple un tableau des pays. Cela aurait, disons, une ID, le nom, le code ISO, la capitale et quelques autres. Chacun de ces quatre premiers sera unique. De plus, si nous voulons que notre système repose sur chacun étant unique, je pense que nous devons définir des contraintes uniques pour chacun. Cela renforce les vérités sur les données sur lesquelles tous les consommateurs peuvent s'appuyer.

Michael Green
la source
Pensez-vous que le design postgresql n'est que le résultat d'une myopie? Oracle, SQL Server, DB2 et autres fournissent tous un moyen de prendre en compte toutes les clés uniques dans une telle situation (à l'aide de l' MERGEinstruction). Le pg ON CONFLICT DO UPDATE n'a été ajouté qu'en 9.5 et est beaucoup plus limité.
appl3r
1
@ appl3r ce n'est qu'un détail d'implémentation. Vous pouvez le faire ON CONFLICT DO NOTHINGsans mentionner de contraintes uniques et il les considérera toutes (et ne fera rien). Lorsque vous voulez le faire ON CONFLICT DO UPDATE, vous devez déclarer une colonne ou une contrainte et une seule. La restriction pourrait être levée dans les versions futures.
ypercubeᵀᴹ
Je suis un peu confus par votre premier paragraphe. Disons que nous avons divisé la table Student (Id, Name, Symbol) de l'OP en S1 (Id, Name) et S2 (Id, Symbol) pour essayer de la transformer en DK / NF. Quelles seraient les contraintes (de domaine et) clés sur S2, et comment garantiraient-elles que chaque élève possède à la fois un identifiant unique et un symbole unique?
Ilmari Karonen
1
La question était (en quelque sorte) "Si plusieurs index UNIQUE sont corrects, pourquoi PostgreSQL nécessite-t-il qu'un index d'arbitre soit spécifié ON CONFLICT ... DO UPDATEet malheureusement cette réponse n'aborde pas ce point.
AndreKR
@AndreKR, il aborde le (en gras): "cette fonctionnalité Postgres a-t-elle été conçue de cette façon, car vous pouvez TOUJOURS restructurer les tables d'une manière où il n'y a qu'un seul index unique?" Vous pouvez certainement ajouter une autre réponse, en abordant le point que vous mentionnez
ypercubeᵀᴹ