IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage SQL Discussion :

Contrainte sur clé unique composée inversée


Sujet :

Langage SQL

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    477
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 477
    Points : 198
    Points
    198
    Par défaut Contrainte sur clé unique composée inversée
    Bonjour à tous et merci d'avance pour votre aide.

    En plus du probléme ci-aprés, j'avoue que même le titre m'a posé problème.
    Je le modifirais si celui-ci ne savére pas être claire.

    J'ai déjà imposé une contrainte d'unicité sur les colonnes A et B.
    Mais j'aimerais étendre cette contrainte même leurs valeurs sont inversé.
    De sorte que si, (A = 8 et B = 7), ( A = 7 et B = 8) ne pourrait être ajouté par la suite.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    A	B	C
    ---------------------
    8	7	17
    7	8	18
    Ici, la ligne 4 ne pourrait être ajouté dans ma table.
    Pour info je suis sur PostgreSQL 9.6.1.

    Merci à vous,

  2. #2
    Membre émérite Avatar de vttman
    Homme Profil pro
    Développeur "couteau mosellan"
    Inscrit en
    Décembre 2002
    Messages
    1 140
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur "couteau mosellan"
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2002
    Messages : 1 140
    Points : 2 286
    Points
    2 286
    Par défaut
    Bonjour Rifton007,

    Je verrais bien dans ce cas la mise en place d'un trigger pour détecter une doublon "inversé " et empêcher l'insertion ?
    Emérite, émérite je ne pense pas ... plutôt dans le développement depuis FORT FORT longtemps, c'est mon job, ça oui
    A part ça ... Il ne pleut jamais en Moselle !

  3. #3
    Membre éclairé Avatar de Arkhena
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 552
    Points : 769
    Points
    769
    Par défaut
    Bonjour,

    D'après la norme SQL, il n'existe que 4 types de contraintes : "unique constraint, a primary key constraint, a referential constraint, or a check constraint."
    Dans votre cas, je regarderai la check constraint. (https://www.postgresql.org/docs/9.6/...eatetable.html)
    and table_constraint is:

    [ CONSTRAINT constraint_name ]
    { CHECK ( expression ) [ NO INHERIT ] |
    UNIQUE ( column_name [, ... ] ) index_parameters |
    PRIMARY KEY ( column_name [, ... ] ) index_parameters |
    EXCLUDE [ USING index_method ] ( exclude_element WITH operator [, ... ] ) index_parameters [ WHERE ( predicate ) ] |
    FOREIGN KEY ( column_name [, ... ] ) REFERENCES reftable [ ( refcolumn [, ... ] ) ]
    [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE action ] [ ON UPDATE action ] }
    [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
    Bonne soirée,

    Arkhena
    A bove ante, ab asino retro, a stulto undique caveto

  4. #4
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 912
    Points
    38 912
    Billets dans le blog
    9
    Par défaut
    Aucune contrainte ne permet de faire de requêtage, or là, il s'agit de vérifier que la combinaison de valeurs de deux colonnes existe de façon inversée, l'utilisation d'une contrainte n'est donc pas possible.

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    477
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juillet 2006
    Messages : 477
    Points : 198
    Points
    198
    Par défaut
    J'ai tout de même essayer avec un CHECK, mais je me rendais compte que c'était pas possible.
    EXCLUDE peut être, mais j'ai jamais trop compris comment cela fonctionne.
    Si non il reste le TRIGGER.

    Merci à vous tous,

  6. #6
    Membre éclairé Avatar de Arkhena
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 552
    Points : 769
    Points
    769
    Par défaut
    Citation Envoyé par escartefigue Voir le message
    Aucune contrainte ne permet de faire de requêtage, or là, il s'agit de vérifier que la combinaison de valeurs de deux colonnes existe de façon inversée, l'utilisation d'une contrainte n'est donc pas possible.
    Effectivement je n'avais pas lu la doc jusqu'au bout...:
    A check constraint specified as a column constraint should reference that column's value only, while an expression appearing in a table constraint can reference multiple columns.Currently, CHECK expressions cannot contain subqueries nor refer to variables other than columns of the current row. The system column tableoid may be referenced, but not any other system column
    (source: https://www.postgresql.org/docs/9.6/...eatetable.html)

    Cependant, la norme SQL ne prévoit pas une telle limitation:
    A table check constraint specifies a search condition. The constraint is violated if the result of the search condition is false for any row of the table (but not if it is unknown).
    Et search condition est définit ainsi:
    <search condition>
    Function
    Specify a condition that is True, False, or Unknown, depending on the value of a <boolean value expression>.
    Format
    <search condition> ::=
    <boolean value expression>
    Syntax Rules
    None.
    Access Rules
    None.
    General Rules
    1) The result of the <search condition> is the result of the <boolean value expression>.
    Conformance Rules
    None.

    Cordialement,

    Arkhena
    A bove ante, ab asino retro, a stulto undique caveto

  7. #7
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 772
    Points : 52 732
    Points
    52 732
    Billets dans le blog
    5
    Par défaut
    Il suffit de rajouter la contrainte CHECK(A<=B)

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  8. #8
    Membre éclairé Avatar de Arkhena
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 552
    Points : 769
    Points
    769
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    Il suffit de rajouter la contrainte CHECK(A<=B)
    Effectivement, c'était tout simple.
    A bove ante, ab asino retro, a stulto undique caveto

  9. #9
    Membre émérite Avatar de vttman
    Homme Profil pro
    Développeur "couteau mosellan"
    Inscrit en
    Décembre 2002
    Messages
    1 140
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur "couteau mosellan"
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2002
    Messages : 1 140
    Points : 2 286
    Points
    2 286
    Par défaut
    Citation Envoyé par Arkhena Voir le message
    Effectivement, c'était tout simple.
    Dans ce message de départ
    De sorte que si, (A = 8 et B = 7), ( A = 7 et B = 8) ne pourrait être ajouté par la suite
    Je vois juste et comprends ? que Rifton007 ne veut pas d'insertion du "couple" (7,8) si (8,7) a déjà été entré
    maintenant si (7,8) qui est déjà présent alors ça serait (8,7) qu'il faudrait rejeter ... d'après ma compréhension évidemment
    Emérite, émérite je ne pense pas ... plutôt dans le développement depuis FORT FORT longtemps, c'est mon job, ça oui
    A part ça ... Il ne pleut jamais en Moselle !

  10. #10
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 772
    Points : 52 732
    Points
    52 732
    Billets dans le blog
    5
    Par défaut
    Et si tu transpose A en B et vice versa ???

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  11. #11
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 760
    Points : 10 541
    Points
    10 541
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Je ne sais pas si sous Postgres la solution que je propose est valide, mais sous SQLServer, ça marche :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CREATE TABLE test_unicite(
    	id INT IDENTITY,
    	A INT NOT NULL,
    	B INT NOT NULL,
    	C AS CASE WHEN A <= B THEN A ELSE B END,
    	D AS CASE WHEN A <= B THEN B ELSE A END
    )
     
    ALTER TABLE test_unicite ADD CONSTRAINT UK_test_unicite UNIQUE(C, D);
     
    INSERT INTO test_unicite(A, B) VALUES (1, 2);
    INSERT INTO test_unicite(A, B) VALUES (2, 1);
    Le principe est simple : j'ai rajouté 2 colonnes calculées, C et D, qui contienne pour l'une le MIN(A, B), pour l'autre MAX(A, B).
    Ainsi, quelque soit l'ordre des valeurs dans A et B, C et D contiennent toujours les mêmes valeurs. Ajoute une contrainte d'unicité dessus et cela fait le boulot. A ma deuxième insertion : violation de clé unique.
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  12. #12
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 154
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    La solution de François, même si elle est plus lourde que celle de Frédéric, me séduit plus : en effet, comme ça on ne bride pas l'ordre des ID.

    Par exemple, un cas concret, ce serait qu'un FILS ne peut avoir qu'un et un seul PERE. Mais surtout, un PERE ne peut pas avoir pour PERE son propre FILS.
    => Dans ce cas, imposer A < B n'est pas possible, ou alors A et B ne sont pas de réels identifiant, car cela les oblige à porter une information de chronologie (ordre de naissance par exemple).

    Sinon, attention aux solutions à base de trigger : il faut s'assurer qu'en cas d'insertion par lot la règle reste vraie (si 1,2 et 2,1 sont présents dans l'ordre d'insertion par exemple).
    On ne jouit bien que de ce qu’on partage.

  13. #13
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 772
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 772
    Points : 52 732
    Points
    52 732
    Billets dans le blog
    5
    Par défaut
    Il n'y a pas de colonne calculées sous PostGreSQL.

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  14. #14
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    Salut
    Deux solutions
    Avec index unique...
    Table
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     create  table tcoupleunique (idc serial primary key, a  smallint  , b smallint)
    index
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE  UNIQUE  INDEX  ukcouple ON tcoupleunique  ((a+b), (a*b))
    Avec exclude
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    create table tcoupleunique2 (idc serial primary key, a  smallint  , b smallint, constraint ukcouple EXCLUDE  ((a+b) with =, (a*b)  with =) )
    @+
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  15. #15
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    A priori on peut créer des index sur expressions :
    11.6. Indexes on Expressions

    On doit donc pouvoir créer ce genre d'index unique (pas de postegresql pour tester) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE  UNIQUE  INDEX  ukcouple ON la_table (CASE WHEN A <= B THEN A ELSE B END, CASE WHEN A <= B THEN B ELSE A END)
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    CREATE  UNIQUE  INDEX  ukcouple ON la_table (least(A, B), greatest(A, B))

  16. #16
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    Salut
    skuatamad
    J'ai testé, la première a besoin de parenthèses pour chaque expression...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((CASE WHEN a <= b THEN a ELSE b END), (CASE WHEN a <= b THEN a ELSE b END))
    la deuxième passe sans problème.
    @+
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  17. #17
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    Salut
    Après test d'insertion, je remarque qu'il y a un problème de position de a et b dans les expressions.
    On doit plutôt faire...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((CASE WHEN a <= b THEN a ELSE b END), (CASE WHEN a <= b THEN b ELSE a END))
    @+
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  18. #18
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 947
    Points : 5 846
    Points
    5 846
    Par défaut
    Exact, mauvais copier coller, merci pour la correction.
    Et merci pour les tests.

  19. #19
    Membre chevronné
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Points : 1 806
    Points
    1 806
    Par défaut
    EDIT bis : ah bein en fait j'ai mis tellement de temps à poster que quelqu'un avait posté une solution concurrente, tant pis pour moi

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Foreign key sur clé primaire composée
    Par mona dans le forum Oracle
    Réponses: 6
    Dernier message: 13/10/2005, 22h36
  2. Réponses: 3
    Dernier message: 28/04/2005, 16h56
  3. [Interbase] Mettre une contrainte sur un champ
    Par mika dans le forum InterBase
    Réponses: 2
    Dernier message: 26/01/2005, 14h04
  4. Hook sur un seul composant d'un TFrom
    Par Neilos dans le forum C++Builder
    Réponses: 2
    Dernier message: 20/11/2004, 17h46
  5. contrainte sur deux champs d'une table
    Par bdkiller dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 17/09/2004, 18h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo