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

Schéma Discussion :

TRADUCTION RELATION (1,n)--(0,n)


Sujet :

Schéma

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 48
    Points : 48
    Points
    48
    Par défaut TRADUCTION RELATION (1,n)--(0,n)
    Bonjour,

    J'aimerais traduire le modèle suivant:

    Une personne appartient minimum à un groupe et maximum à N groupes.
    Un groupe peut exister seul (n'appartenir à aucun tuple de la table personne) ou appartenir à N personnes.

    PERSONNE (1,n) ------ (0,n) GROUPE

    Je présume que je dois créer une table de relation, reprenant 2 propriétés la clé primaire de personne et la clé primaire de groupe qui forment ensemble la clé primaire de cette table de relation.

    Mais dans ce cas, une personne peut exister sans avoir de groupe... Or je voudrais qu'au minimum elle en aie un...

    Est-ce que qqu'un pourrait m'éclairer sur cette question?

    D'avance merci

  2. #2
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 112
    Points : 31 586
    Points
    31 586
    Billets dans le blog
    16
    Par défaut Structures et contraintes
    Bonsoir superviny,


    Citation Envoyé par superviny Voir le message
    Je présume que je dois créer une table de relation, reprenant 2 propriétés la clé primaire de personne et la clé primaire de groupe qui forment ensemble la clé primaire de cette table de relation.
    Exactement. En l’occurrence vous traitez de l’aspect structurel de la base de données. Par exemple, dans le cadre de la théorie relationnelle, on déclare ainsi les structures (langage Tutorial D) :

    Variable GROUPE :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    VAR GROUPE BASE RELATION
        {
         GroupeId       INTEGER,
         GroupeNom      CHAR
        } 
        KEY {GroupeId} ;

    Variable PERSONNE :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    VAR PERSONNE BASE RELATION
        {
         PersonneId       INTEGER,
         PersonneNom      CHAR
        } 
        KEY {PersonneId} ;

    Pour brancher les groupes et les personnes :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    VAR PERSONNE_GROUPE BASE RELATION
        {
         GroupeId       INTEGER,
         PersonneId     INTEGER
        } 
        KEY {GroupeId, PersonneId} 
        FOREIGN KEY {GroupeId} REFERENCES GROUPE 
        FOREIGN KEY {PersonneId} REFERENCES PERSONNE ;

    Mais une base de données relationnelle n’est pas que structure, il faut aussi déclarer chaque contrainte dont elle fait l’objet, à l’instar de celle que vous évoquez :
    Une personne appartient au moins à un groupe.

    Traduction en Tutorial D :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CONSTRAINT C001
        PERSONNE {PersonneId} = PERSONNE_GROUPE {PersonneId} ;
    Ce qui se traduirait (hypothétiquement) ainsi en SQL :
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CREATE ASSERTION C001 CHECK 
        (SELECT PersonneId FROM PERSONNE = SELECT DISTINCT PersonneId FROM PERSONNE_GROUPE) ;

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 48
    Points : 48
    Points
    48
    Par défaut
    Merci beaucoup pour votre réponse...

    Je commence à entrevoir la solution...

    Je suis en MySQL et j'ai écris cette requête:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ALTER TABLE 
    PERSONNE 
    ADD CONSTRAINT C001 CHECK 
    ( SELECT 
      ID_PERSONNE 
      FROM 
      PERSONNE 
      WHERE ID_PERSONNE = (SELECT DISTINCT 
                                        PERSONNE_ID_PERSONNE 
                                        FROM 
                                        PERSONNE_HAS_GROUPE
                                      )
    );
    Ca passe sans erreur mais ça semble n'avoir aucun effet...
    Je présume que ce n'est pas supporté en MySQL et qu'il va falloir trouver une "parade"...

  4. #4
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 112
    Points : 31 586
    Points
    31 586
    Billets dans le blog
    16
    Par défaut
    Hum... Je n’utilise pas MySQL, donc ne peux pas porter de jugement sur son comportement. Quoi qu’il en soit, dans le cadre de la norme SQL on déclare les contraintes sous forme d’assertions :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    CREATE ASSERTION C001 CHECK 
        (NOT EXISTS 
            (SELECT  '' 
             FROM PERSONNE AS x 
             WHERE NOT EXISTS 
                  (SELECT  '' 
                   FROM PERSONNE_GROUPE AS y 
                   WHERE x.PersonneId = y.PersonneId)))
          DEFERRABLE INITIALLY DEFERRED ;

    Avec cette assertion, on demande au SGBD de veiller au respect de la contrainte C001, mais aussi d’attendre qu’on lui donne feu vert (clause INITIALLY DEFERRED).

    On a donc le loisir d’exécuter les INSERT classiques :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    INSERT INTO PERSONNE (PersonneId, PersonneNom) VALUES (1, 'Raoul') ;
     
    INSERT INTO PERSONNE_GROUPE (GroupeId, PersonneId) VALUES (1, 1) ;

    Et l’on demande enfin au SGBD de déclencher les contrôles (si on reste muet, ces contrôles auront lieu au moment du COMMIT) :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    SET CONSTRAINTS ALL IMMEDIATE ;

    Le problème est qu’entre le paquet d’inserts et le déclenchement des contrôles, on peut commettre des étourderies et fantaisies diverses : la technique proposée par la norme SQL n’est pas vraiment satisfaisante.

    Concernant MySQL, je lis ceci dans la doc (MySQL 5.6 Reference Manual) :
    "The CHECK clause is parsed but ignored by all storage engines."

  5. #5
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 112
    Points : 31 586
    Points
    31 586
    Billets dans le blog
    16
    Par défaut
    Suite...

    Dans le cas général SQL, une alternative pourrait consister à mettre en oeuvre une vue :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    CREATE VIEW PERSONNE_GROUPE_V (PersonneId, PersonneNom, GroupeId) 
         AS SELECT   x.PersonneId, x.PersonneNom, y.GroupeId
            FROM     PERSONNE AS x INNER JOIN PERSONNE_GROUPE AS y 
                     ON  x.PersonneId = y.PersonneId ;
    Vue servant notamment pour les INSERT. Effectuons donc un insert d’une personne (Raoul, faisant partie du groupe 1) :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    INSERT INTO PERSONNE_GROUPE_V VALUES (1, 'Raoul', 1) ;
    Maintenant, soit le SGBD accepte les mises à jour des vues de jointure, soit il les refuse. Comme j’utilise MS SQL Server 2005, c’est niet, je passe donc par un trigger pour intercepter les inserts et effectuer les ventilations qui vont bien :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CREATE TRIGGER PERSONNE_GROUPE_V_INSERT ON PERSONNE_GROUPE_V INSTEAD OF INSERT AS
        INSERT INTO PERSONNE (PersonneId, PersonneNom) 
               SELECT  PersonneId, PersonneNom
               FROM    INSERTED
        INSERT INTO PERSONNE_GROUPE (GroupeId, PersonneId) 
               SELECT  GroupeId, PersonneId
               FROM    INSERTED ;
    C’est quand même moins léger que la déclaration d’une contrainte façon Tutorial D, d’autant que — le degré d’abstraction en SQL étant moins élevé — on doit être vigilant sur les mises à jour en général... Par exemple, si l’on n’y prenait garde, on pourrait enfreindre la contrainte C001 en supprimant intempestivement des lignes de PERSONNE_GROUPE : il faut donc prévoir un trigger ad-hoc pour que la contrainte soit respectée :

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    CREATE TRIGGER PERSONNE_GROUPE_DELETE ON PERSONNE_GROUPE AFTER DELETE AS
      SELECT ''
      FROM   PERSONNE AS x 
              JOIN PERSONNE_GROUPE AS y ON x. PersonneId = y. PersonneId
      IF @@rowcount = 0
      BEGIN 
        Raiserror ('Table PERSONNE : rejet du DELETE (viol de la contrainte 1,N !)',16,1) 
        ROLLBACK
      RETURN
      END ;

    Mais, en ce qui concerne les inserts, je ne sache pas que MySQL permette de déclarer des triggers sur des vues...

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 48
    Points : 48
    Points
    48
    Par défaut
    Bonjour,

    Merci pour ton aide.

    Je viens d'essayer de créer un trigger. Je ne l'ai jamais fait mais voici ce que j'ai écrit:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    DELIMITER //
    CREATE TRIGGER PERSONNE_GROUPE_V_INSERT BEFORE INSERT
    ON PERSONNE_GROUPE_V
    FOR EACH ROW
    BEGIN
        INSERT INTO PERSONNE (ID_PERSONNE, PE_NOM) 
               SELECT  
               ID_PERSONNE, PE_NOM           
               FROM    INSERTED ;
        INSERT INTO PERSONNE_HAS_GROUPE (PERSONNE_ID_PERSONNE, GROUPE_ID_GROUPE) 
               SELECT  PERSONNE_ID_PERSONNE, GROUPE_ID_GROUPE
               FROM    INSERTED ;
    END;
    //
    DELIMITER ;
    Et j'obtiens l'erreur suivante:
    ERROR 1347 (HY000): 'personne_groupe_v' is not BASE TABLE

    Et de faite dans la doc je trouve ceci:

    You cannot associate a trigger with a TEMPORARY table or a view.

    Et malheureusement MySQL n'accepte pas non plus de mettre à jour directement depuis la vue...
    Doc (extrait choisi):

    For a multiple-table updatable view, INSERT can work if it inserts into a single table. DELETE is not supported.

  7. #7
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 112
    Points : 31 586
    Points
    31 586
    Billets dans le blog
    16
    Par défaut
    Bonsoir superviny,


    Citation Envoyé par superviny Voir le message
    Et de fait dans la doc je trouve ceci:

    You cannot associate a trigger with a TEMPORARY table or a view.

    Et malheureusement MySQL n'accepte pas non plus de mettre à jour directement depuis la vue...
    Doc (extrait choisi) :

    For a multiple-table updatable view, INSERT can work if it inserts into a single table. DELETE is not supported.
    Vous confirmez hélas ! ce que j’avais écrit :
    Citation Envoyé par fsmrel Voir le message
    Mais, en ce qui concerne les inserts, je ne sache pas que MySQL permette de déclarer des triggers sur des vues...
    C'est donc un démenti de la prétendue complétude affirmée par les promoteurs de MySQL qui écrivent :
    « 7. Des fonctions complètes de développement d’applications

    L’une des raisons pour lesquelles MySQL est la base de données open source la plus populaire au monde est qu’elle est adaptée à tous les besoins de développement d’applications. Au sein de la base de données, on pourra bénéficier de procédures stockées, de déclencheurs, de fonctions, de vues, de curseurs, d’un SQL à la norme ANSI, etc. »

    Nonobstant les allégations mysqlesques, vous serez donc contraint à faire respecter la contrainte de façon applicative...

    Cela ne vous consolera pas, mais pour que vous mesuriez la distance qui sépare MySQL du Modèle Relationnel de Données (cela vaut du reste pour les autres SGBD SQL, sans oublier la norme elle-même...), voici pour résumer comment garantir la cardinalité 1,N en utilisant Tutorial D :

    Déclaration des variables (cf. mon 1er message) :

    Variable GROUPE :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    VAR GROUPE BASE RELATION
        {
         GroupeId       INTEGER,
         GroupeNom      CHAR
        } 
        KEY {GroupeId} ;

    Variable PERSONNE :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    VAR PERSONNE BASE RELATION
        {
         PersonneId       INTEGER,
         PersonneNom      CHAR
        } 
        KEY {PersonneId} ;

    Pour brancher les groupes et les personnes :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    VAR PERSONNE_GROUPE BASE RELATION
        {
         GroupeId       INTEGER,
         PersonneId     INTEGER
        } 
        KEY {GroupeId, PersonneId} 
        FOREIGN KEY {GroupeId} REFERENCES GROUPE 
        FOREIGN KEY {PersonneId} REFERENCES PERSONNE ;

    Déclaration de la contrainte traduisant la règle selon laquelle :
    Une personne appartient au moins à un groupe.

    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CONSTRAINT C001
        PERSONNE {PersonneId} = PERSONNE_GROUPE {PersonneId} ;

    Venons-en à l’œuf de Christophe Colomb, c'est-à-dire à un principe très simple dont les auteurs de la norme SQL (abréviation de Sorry Query Language) n’ont même pas eu l’idée de s’inspirer... Tutorial D met à notre disposition l’affectation multiple, laquelle permet de regrouper en une seule instruction un nombre quelconque d’instructions élémentaires.

    Dans le code, deux instructions sont élémentaires quand elles sont séparées par une virgule et la dernière de celles-ci suivie d’un point-virgule. Les contrôles faisant l’objet des contraintes ne sont déclenchés qu’à la détection du point-virgule, après à quoi l’utilisateur pourra reprendre le contrôle des opérations.

    Mettons à jour simultanément les relvars PERSONNE et PERSONNE_GROUPE :
    Code D : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    INSERT PERSONNE RELATION {TUPLE
                                   {
                                    PersonneId        1,
                                    PersonneNom       'Raoul'
                                   }
                             },     /* virgule : séparateur d’opérations */
    INSERT PERSONNE_GROUPE RELATION {TUPLE
                                          {
                                           GroupeId            1,
                                           PersonneId          1
                                          }
                                    } ;     /* point-virgule : fin de la liste des opérations*/
    Cette fois-ci la contrainte C001 ne verra rien à redire car la cardinalité 1,N est bien place, Raoul fait bien partie d’un groupe.

    On n’a pas eu besoin de se creuser les méninges et en passer par des palliatifs plus ou moins tarabiscotés...

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 48
    Points : 48
    Points
    48
    Par défaut
    Bonjour fsmrel,

    De fait dans un cas concret on se rend plus vite compte des limites de MySQL.

    Merci néanmoins pour toutes ces informations que vous m'avez apportées et qui m'ont rapidement permises d'arriver à ces conclusions.

    Merci aussi pour ce cours accéléré sur les contraintes qui me serviront sans nul doute.

  9. #9
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 112
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Spécialiste en bases de données
    Secteur : Conseil

    Informations forums :
    Inscription : Septembre 2006
    Messages : 8 112
    Points : 31 586
    Points
    31 586
    Billets dans le blog
    16
    Par défaut
    Hello superviny,


    Ça sera peut-être bon avec la version quarante douze de MySQL ? (Mais sans doute serez-vous passé à autre chose... )

    En attendant, bonne route !

Discussions similaires

  1. Réponses: 2
    Dernier message: 31/08/2010, 20h01
  2. [MPD] Traduction de la relation d'héritage.
    Par @omzo dans le forum Schéma
    Réponses: 10
    Dernier message: 05/05/2010, 12h58
  3. Traduction en C d'une relation fonctionnelle
    Par Lazypanda dans le forum Débuter
    Réponses: 2
    Dernier message: 16/12/2008, 10h35
  4. Traduction
    Par PierDIDI dans le forum Composants VCL
    Réponses: 3
    Dernier message: 17/09/2002, 23h43
  5. Changement de langue dynamique (D6 et outils de traduction)
    Par agon dans le forum Composants VCL
    Réponses: 4
    Dernier message: 17/09/2002, 16h15

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