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 :

Schema BdD : FK sur plusieurs tables ?


Sujet :

Schéma

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2013
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2013
    Messages : 65
    Points : 39
    Points
    39
    Par défaut Schema BdD : FK sur plusieurs tables ?
    Bonjour,

    J'ai le schéma d'une base à mettre en place pour un cours (On va sûrement utiliser Postgré mais je penses que ça n'a pas d'importance pour la problématique de ce post).
    On doit développer un programme (appelé "agent") qui sera installé sur plusieurs postes et qui devra consulter une BdD pour savoir les tâches qu'il doit y effectuer

    Base de Données:
    Nom : AIS-DB-v2.PNG
Affichages : 2310
Taille : 36,6 Ko
    Dans le schéma :
    • "Devices" : contiendra tous les postes/agent(même chose car un agent est installé sur UN poste)
    • "Actions" : contiendra toutes les tâches possibles, un genre de répertoire global de toutes les tâches qu'on peut assigner à un agent
    • "Tasks" : contiendra les tâches d'un agent. Permet à chaque agent de savoir quelle(s) action(s) il doit effectier. Une Action peut-être associée à plusieurs agents.


    Mon soucis c'es que je dois aussi gérer les OS et cela me pose quelques difficultés.
    Pour moi un OS c'est une famille et une version, sachant qu'une version à forcément une famille :
    • "Families" : contienda la liste de toutes les familles (Windows, Linux, Mac, [...])
    • "Version" : contiendra les OS disponibles en associant "name" (vista, xp, 10, 7, 2012R2, [...]) avec une famille via la FK, ce qui donnera par exemple (par exemple "Windows 10", "Windows 2012 R2", [...])


    Chaque device a un OS, représenté dans le schéma ci-dessus par la FK "Devices.idVersion" qui pointe vers "Versions.idVersion"
    Je penses que c'est correct, êtes-vous d'accord ? je suis preneur d'avis!

    Le truc qui me bloque vraiment :
    Une Actions peut ne pas être compatible avec toutes les Version ou Famillies et je ne vois pas comment représenter ça.
    Je penses que j'ai forcément besoin d'une FK dans la table "Actions" (dans le schéma "Actions.id?").
    Par contre ça signifie que cette FK doit pouvoir venir de deux tables différentes : "Version" et "Families"
    Exemple
    1. Action1 peut être assignée à n'importe quel agent : "Actions.id?" = NULL
    2. Action2 ne peut être assignée qu'a des machines "Windows", donc : "Actions.id?" = "Families.idFamily"
    3. Action3 ne peut être assignée qu'a des machines "Windows 2012 R2", donc : "Actions.id?" = "Versions.idVersion"


    Quelqu'un a-t-il une idée ?
    Merci d'avance !

    P.S : J'ai pensé a une autre représentation des OS? Je penses que celui haut-dessus est mieux mais on ne sait jamais, voici la v1 :
    Nom : AIS-DB-v1.PNG
Affichages : 1035
Taille : 38,8 Ko

  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 002
    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 002
    Points : 30 906
    Points
    30 906
    Billets dans le blog
    16
    Par défaut
    Citation Envoyé par Firlfire Voir le message
    J'ai pensé a une autre représentation des OS
    Cette représentation est inessentielle et redondante (nom des OS) : à éviter.


    Il faut appeler un chat un chat, en l’occurrence nommer les liens représentant les contraintes entre les actions et les familles d’une part et les versions d’autre part :

    Nom : Firlfire_mld.png
Affichages : 1935
Taille : 20,0 Ko

    Dans le cadre de la norme SQL, les contraintes seront vérifiées par le SGBD au moment de l’affectation des tâches, grâce aux assertions (contraintes) qu’on aura déclarées. Un exemple valant pour les familles :

    CREATE ASSERTION ASSERT01 CHECK 
    (EXISTS
        SELECT *
        FROM   POSTE as x
          JOIN TACHE as y on x.posteId = y.posteId
          JOIN ACTION_CONTRAINTE_PAR_FAMILLE as z on y.actionId = z.actionId
           AND x.familleId = z.familleId
    )
    
    Avec les SGBD à la traîne, il faudra en passer par des triggers.

    Par assertion (ou trigger...) on pourra aussi vérifier que les actions contraintes par familles et les actions contraintes par versions sont exclusives.
    (a) Faites simple, mais pas plus simple ! (A. Einstein)
    (b) Certes, E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
    => La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

    __________________________________
    Bases de données relationnelles et normalisation : de la première à la sixième forme normale
    Modéliser les données avec MySQL Workbench
    Je ne réponds pas aux questions techniques par MP. Les forums sont là pour ça.

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2013
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2013
    Messages : 65
    Points : 39
    Points
    39
    Par défaut
    Bonjour, et merci pour la réponse!

    Il y a un point que je ne comprends pas dans votre schéma : pourquoi "familleId" est présent dans "POSTE" ? (idem dans ACTION_CONTRAINTE_PAR_VERION)
    Je ne vois pas l'utilité car comme VERSION.versionId est une PK elle sera unique das la table, donc si POSTE ne contient que versionID il est possible de remonter a FAMILLE (avec le même nombre de jointure)

    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    select p.posteId, p.posteNom, f.familleNom, v.versionNom
    	from POSTE p
    	join VERSION v on p.versionId = v.versionId
    	join FAMILLE f on p.familleId = f.familleID
     
    -- ou
     
    select p.posteId, p.posteNom, f.familleNom, v.versionNom
    	from POSTE p
    	join VERSION v on p.versionId = v.versionId
    	join FAMILLE f on v.familleId = f.familleID

  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 910
    Points
    38 910
    Billets dans le blog
    9
    Par défaut
    bonjour.

    La version est une entité-type dite faible : elle n'existe qu'au travers de la famille à laquelle elle se rattache. Par conséquent, la version est identifiée relativement à la famille. C'est la raison pour laquelle, on trouve dans la table version, un identifiant primaire (PK) composé de l'identifiant de la famille complété de l'identifiant de la version. C'est ce qu'on appelle l'identification relative.

    Et par conséquence, vu que pour un poste il n'y a qu'une seule version, l'identifiant de la version se retrouve dans la table poste, cet identifiant est bien id_famille + id_version

    Point important : l'identifiant de version seul n'est pas unique, il faut l'associer à l'identifiant de famille pour avoir l'unicité

  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 002
    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 002
    Points : 30 906
    Points
    30 906
    Billets dans le blog
    16
    Par défaut
    Bonsoir,

    Citation Envoyé par Firlfire
    Il y a un point que je ne comprends pas dans votre schéma : pourquoi "familleId" est présent dans "POSTE" ? (idem dans ACTION_CONTRAINTE_PAR_VERSION)
    Je ne vois pas l'utilité car comme VERSION.versionId est une PK elle sera unique dans la table, donc si POSTE ne contient que versionID il est possible de remonter a FAMILLE.
    Il est exact que la présence de l’attribut familleId dans POSTE n’est pas nécessaire. Le MLD que j’ai présenté est en fait dérivé d’un MCD dans lequel VERSION et POSTE sont des entités-types considérées comme faibles (weak entity-types, alias characteristics chez Codd), c’est ce qu’a expliqué escartefigue. Ce type de modélisation est surtout utile quand les MCD comportent des boucles (cf. par exemple le post Gestion Facturation et devis), ce qui n’est pas le cas du vôtre (mais presque...)

    En considérant maintenant ces entités-types comme fortes (regular entity-types, alias kernels chez Codd), alors les tables SQL sont les suivantes :

    CREATE TABLE ACTION 
    (
          actionId                 INT                      NOT NULL,
          actionNom                VARCHAR(48)              NOT NULL,
       CONSTRAINT ACTION_PK PRIMARY KEY (actionId),
       CONSTRAINT ACTION_AK UNIQUE (actionNom)
    ) ;
    
    CREATE TABLE FAMILLE 
    (
          familleId                INT                      NOT NULL,
          familleNom               VARCHAR(48)              NOT NULL,
       CONSTRAINT FAMILLE_PK PRIMARY KEY (familleId),
       CONSTRAINT FAMILLE_AK UNIQUE (familleNom)
    ) ;
    
    CREATE TABLE ACTION_CONTRAINTE_PAR_FAMILLE 
    (
          actionId                 INT                      NOT NULL,
          familleId                INT                      NOT NULL,
       CONSTRAINT ACTION_CONTRAINTE_PAR_FAMILLE_PK PRIMARY KEY (actionId, familleId),
       CONSTRAINT ACTION_CONTRAINTE_PAR_FAMILLE_ACTION_FK FOREIGN KEY (actionId)
          REFERENCES ACTION (actionId),
       CONSTRAINT ACTION_CONTRAINTE_PAR_FAMILLE_FAMILLE_FK FOREIGN KEY (familleId)
          REFERENCES FAMILLE (familleId)
    ) ;
    
    CREATE TABLE VERSION 
    (
          familleId                INT                      NOT NULL,
          versionId                INT                      NOT NULL,
          versionNom               VARCHAR(48)              NOT NULL,
       CONSTRAINT VERSION_PK PRIMARY KEY (versionId),
       CONSTRAINT VERSION_FAMILLE_FK FOREIGN KEY (familleId)
          REFERENCES FAMILLE (familleId)
    ) ;
    
    CREATE TABLE ACTION_CONTRAINTE_PAR_VERSION 
    (
          actionId                 INT                      NOT NULL,
          familleId                INT                      NOT NULL,
          versionId                INT                      NOT NULL,
       CONSTRAINT ACTION_CONTRAINTE_PAR_VERSION_PK PRIMARY KEY (actionId, familleId, versionId),
       CONSTRAINT ACTION_CONTRAINTE_PAR_VERSION_ACTION_FK FOREIGN KEY (actionId)
          REFERENCES ACTION (actionId),
       CONSTRAINT ACTION_CONTRAINTE_PAR_VERSION_VERSION_FK FOREIGN KEY (versionId)
          REFERENCES VERSION (versionId)
    ) ;
    
    CREATE TABLE POSTE 
    (
          posteId                  INT                      NOT NULL,
          posteNom                 VARCHAR(48)              NOT NULL,
          versionId                INT                      null,
       CONSTRAINT POSTE_PK PRIMARY KEY (posteId),
       CONSTRAINT POSTE_AK UNIQUE (posteNom),
       CONSTRAINT POSTE_VERSION_FK FOREIGN KEY (versionId)
          REFERENCES VERSION (versionId)
    ) ;
    
    CREATE TABLE TACHE 
    (
          actionId                 INT                      NOT NULL,
          posteId                  INT                      NOT NULL,
       CONSTRAINT TACHE_PK PRIMARY KEY (actionId, posteId),
       CONSTRAINT TACHE_ACTION_FK FOREIGN KEY (actionId)
          REFERENCES ACTION (actionId),
       CONSTRAINT TACHE_POSTE_FK FOREIGN KEY (posteId)
          REFERENCES POSTE (posteId)
    ) ;
     
    Autrement dit, la contrainte initiale, version identification relative :

    CREATE ASSERTION ASSERT01 CHECK 
    (EXISTS
        SELECT *
        FROM   POSTE as x
          JOIN TACHE as y on x.posteId = y.posteId
          JOIN ACTION_CONTRAINTE_PAR_FAMILLE as z on y.actionId = z.actionId
           AND x.familleId = z.familleId
    ) ;
    
    Peut être remplacée par la suivante :

    CREATE ASSERTION ASSERT01 CHECK 
    (EXISTS
        SELECT *
        FROM   POSTE as x
          JOIN VERSION as v on x.versionId = v.versionId
          JOIN TACHE as y on x.posteId = y.posteId
          JOIN ACTION_CONTRAINTE_PAR_FAMILLE as z on y.actionId = z.actionId
           AND v.familleId = z.familleId
    ) ;
    
    Exemple de viol de la contrainte : affectation de l’action a2 au poste p1 référençant la version v1 qui référence la famille f1, tandis que dans ACTION_CONTRAINTE_PAR_FAMILLE, l’action a2 référence la version v2 qui référence la famille f2.

    insert into ACTION values
        (1, 'action 1') 
      , (2, 'action 2') 
    ;
    insert into FAMILLE values
        (1, 'famille 1') 
      , (2, 'famille 2') 
    ;
    insert into VERSION (familleId, versionId, versionNom) values
        (1, 1, 'famille 1, version 1')
      , (2, 2, 'famille 2, version 2')
    ;
    insert into ACTION_CONTRAINTE_PAR_FAMILLE (actionId, familleId) values
        (2, 2)
    ;
    insert into ACTION_CONTRAINTE_PAR_VERSION (actionId, familleId, versionId) values
        (1, 1, 1)
    ;
    insert into POSTE (posteId, posteNom, versionId) values
        (1, 'poste 1', 1) 
    ;
    insert into TACHE (actionId, posteId) values
        (2, 1)   /*  action 2, poste 1 qui => version 1 => famille 1 */
    ;
    
    Mais après tout, si la paire (a2, p1) de la table TACHE induit la paire (a2, f1) et que cette paire n’est pas contrainte à exister au préalable dans ACTION_CONTRAINTE_PAR_FAMILLE, alors la contrainte ASSERT01 peut être supprimée. A vous de voir.
    (a) Faites simple, mais pas plus simple ! (A. Einstein)
    (b) Certes, E=mc², mais si on discute un peu, on peut l’avoir pour beaucoup moins cher... (G. Lacroix, « Les Euphorismes de Grégoire »)
    => La relativité n'existerait donc que relativement aux relativistes (Jean Eisenstaedt, « Einstein et la relativité générale »)

    __________________________________
    Bases de données relationnelles et normalisation : de la première à la sixième forme normale
    Modéliser les données avec MySQL Workbench
    Je ne réponds pas aux questions techniques par MP. Les forums sont là pour ça.

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Lycéen
    Inscrit en
    Mars 2013
    Messages
    65
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Mars 2013
    Messages : 65
    Points : 39
    Points
    39
    Par défaut
    Bonjour, et merci pour vos réponses.

    Nous avions un problème de "vocabulaire" dans notre projet. "OS" était ambigü, nous avons résolu ce problème en l'appelant "System" et nous avons changé notre regard dessus :
    L'agent sera installé sur un Device. Ce Device possède un Système, et ce dernier possède lui même:
    - Une Ditribution (ex : Microsoft Windows 10 Professionnel)
    - Des caractéristique propres à ce Device et cette distribution (par exemple, hostname = "Mon PC" avec une architecture 64b

    Quant à elle la distribution possède une Plateforme (Windows / Mac / Linux / ...)
    Concernant les restrictions des tâches, nous les avons simplement limitées à une version. Si une Action doit être limitée à une Plateforme , alors elle sera limitée à toutes les Version de la Plateforme (on insérera plusieurs ligne dans la table)

    Ci-dessous ce que cela nous donne (les contraintes de FK sont représentées par "ref: [...]").
    J'ai tout de même 2 questions :
    1. Mon MCD vous parait-il convenable ?
    2. Ca signifie que dans cette DB, UN Device possède UN System, et UN System n'appartient qu'a UN Device (en gros One-To-One), la représentation est-elle correcte ? Ne faut-il pas plutôt que j'enlève la FK Devices.systemId et que ma clé primaire dans Systems s'appelle aussi "deviceId" ? (qui bien entendu sera une FK vers Devices.deviceId) En soit ce sont la même chose, mais dans deux contextes différents : une machine est composée d'un Device (HP Pro Book [...]) sur lequel est installé un System (Windows 7 Pro, 32b, build 1734, uuid [xxx]).


    Code SQL : 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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    Table Actions {
      actionId integer [pk, not null]
      nom [not null, unique]
      [...]
    }
     
    Table Platforms {
      platformId integer [pk, not null]
      name varchar(60) [not null, unique]
    }
     
    Table Distributions {
      distributionId integer [pk, not null]
      platformId integer [not null, ref: > Platforms.platformId]
      name varchar(60) [not null]
    }
     
    Table ActionsByDistributions {
      actionId integer [pk, not null, ref: > Actions.idAction]
      distributionId integer [pk, not null, ref: > Distributions.distributionId]
    }
     
    Table Systems {
      systemId integer [pk, not null]
      distributionId integer [not null, ref: > Distributions.distributionId]
      [...]
    }
     
    Table Devices {
      deviceId integer [pk, not null]
      systemId integer [not null, ref: > Systems.systemId]
      [...]
    }
     
    Table Tasks {
      deviceId integer [pk, not null, ref: > Devices.deviceId]
      actionId integer [pk, not null, ref: > Actions.actionId]
    }

Discussions similaires

  1. select sur plusieurs table, question sur jointure
    Par Schulman dans le forum Langage SQL
    Réponses: 7
    Dernier message: 03/09/2004, 13h54
  2. Encore une requête complexe sur plusieurs tables
    Par DenPro dans le forum Langage SQL
    Réponses: 5
    Dernier message: 09/12/2003, 19h05
  3. order by sur plusieurs tables
    Par Mad_Max dans le forum Requêtes
    Réponses: 2
    Dernier message: 09/12/2003, 12h17
  4. Requête complexe sur plusieurs table
    Par DenPro dans le forum Langage SQL
    Réponses: 13
    Dernier message: 25/11/2003, 17h50
  5. A propos d'une requête SQL sur plusieurs tables...
    Par ylebihan dans le forum Langage SQL
    Réponses: 2
    Dernier message: 14/09/2003, 16h26

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