1
votes

Valeur unique SQL (PostgreSQL) entre les groupes

J'ai une table avec les colonnes val_A, val_B. Ayant une exigence que je ne peux faire que des insertions (pas de mises à jour / suppressions et je voudrais éviter les déclencheurs et les procédures de stockage).

Comment je peux atteindre une telle exigence que la valeur de la colonne val_A doit être unique, mais pas pour la table entière mais uniquement pour les groupes basés sur val_B. En d'autres termes, je peux avoir de nombreuses entrées avec val_A = 1 pour val_B = 1, mais dans ce cas je ne peux pas avoir val_A = 1 avec val_B! = 1;

Par exemple:

+-------+-------+---------------------+
| val_A | val_B |       Comment       |
+-------+-------+---------------------+
|     1 |     1 |                     |
|     2 |     1 |                     |
|     1 |     1 | This is Allowed     |
|     1 |     2 | This is not allowed |
+-------+-------+---------------------+

EDIT # 1 La solution que je recherche devrait fonctionner pour les inserts actuels. J'essayais quelque chose de similaire à la réponse de Davide Anghileri , mais cela a échoué dans des scénarios d'insertion simultanés.


0 commentaires

3 Réponses :


0
votes

Vous pouvez utiliser un index de filtrage unique:

create unique index myidx 
    on mytable(val_a)
    where (val_b is distinct from 1)

Cela autorise les doublons dans val_a uniquement sur les lignes où val_b a la valeur 1 .


1 commentaires

Merci, mais je ne peux pas fixer uniquement la valeur 1. Cela doit être une solution générique.



1
votes

Vous pouvez placer la condition de vérification dans une clause WHERE. Voici un exemple:

 val_A=other_table.val_A AND val_B!=other_table.val_B

Vous pouvez prendre les nombres à insérer (par exemple 1, 2) d'une autre table si vous le souhaitez. Le nombre de la clause Where doit également être défini sur l'autre table:

INSERT INTO table_name(val_A, val_B)
SELECT 1, 2
WHERE NOT EXISTS (SELECT * FROM table_name WHERE val_A=1 AND val_B!=2)

Avec cette condition, vous pouvez insérer 1,1 mais pas 1,2 puisque vous avez déjà un enregistrement avec le même val_A et un val_B différent.


1 commentaires

Merci, s'il vous plaît voir mon message original EDIT # 1



1
votes

C'est délicat mais vous pouvez créer un index unique sur une expression - et utiliser le fait que Postgres autorise la répétition des valeurs NULL dans un index unique.

Donc:

create unique index unq_t_val_a_val_b on
    (least(val_a, val_b), greatest(val_a, val_b))
    where val_a <> val_b;

Lorsque les valeurs sont différentes , least() et greatest() crée un index avec deux clés avec les valeurs dans l'ordre. Lorsque les valeurs sont identiques, les clés sont NULL et ne font donc pas vraiment partie de l'index unique.

Vous pouvez également le faire avec le filtrage:

create unique index unq_t_val_a_val_b on
    (case when val_a <> val_b then least(val_a, val_b) end,
     case when val_a <> val_b then greatest(val_a, val_b) end
    );


0 commentaires