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 :

Etude de cas : Chauffeur - Voiture et relation N,N


Sujet :

Schéma

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Août 2009
    Messages : 97
    Points : 59
    Points
    59
    Par défaut Etude de cas : Chauffeur - Voiture et relation N,N
    Bonsoir,

    Je me pose une question sur le début de mon MCD.

    J'ai une application avec des chauffeurs qui réservent des voitures disponibles. Je n'explique pas tout le projet car ce n'est pas nécessaire pour ce cas.
    J'ai élaboré le début du MCD avec 2 tables (Drivers et Cars).

    Nom : bdd_mcd.PNG
Affichages : 1668
Taille : 10,5 Ko

    Dans ma logique :
    - Un chauffeur peut conduire aucune à plusieurs voitures (0,N)
    - Une voiture peut être conduite par aucun ou plusieurs chauffeurs (0,N)

    Avec mes relations, j'ai une nouvelle table "To Drive" qui se créé en MLD.

    Actuellement dans cette table, j'ai deux clés primaires sur la voiture (id_car) et le chauffeur (id_driver).

    Or, si je laisse le MCD tel quel, un chauffeur ne peut conduire qu'une seule voiture ET une voiture ne peut être conduit que par un seul et unique chauffeur.
    Cependant, un chauffeur peut en conduire plusieurs par jours et une voiture conduite par plusieurs chauffeurs (d'où mes DateTime_Departure et DateTime_Arrival).

    Il me semble que ce n'est pas top de rajouter une clé primaire sur les deux champs DATETIME...

    Faut-il rajouter un id_course dans la table "To drive" ? Ou créer vraiment une entité "Course" à la place ? Quelle différence ?

    Le but de la manœuvre dans l'application :
    Lorsqu'un chauffeur démarre l'application pour réserver une voiture, seules les voitures dispos lui sont proposées.
    La table "To Drive" pourra être utilisée par la suite pour être interrogée afin de proposer des statistiques (sur les voitures, sur une journée, sur un chauffeur etc...).

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

    Le sujet est intéressant à cause de la dimension temporelle à prendre en compte. Ceci dit, quelques remarques :


    Citation Envoyé par matheous Voir le message
    J'ai élaboré le début du MCD avec 2 tables (Drivers et Cars).
    Dans un MCD on n’a pas de tables, mais des types d’entités (ou entités-types ou classes d’entités, etc.)


    Citation Envoyé par matheous Voir le message
    Avec mes relations, j'ai une nouvelle table "To Drive" qui se créé en MLD.
    Actuellement dans cette table, j'ai deux clés primaires sur la voiture (id_car) et le chauffeur (id_driver).
    Une table ne peut pas avoir deux clés primaires. En réalité la table TO_DRIVE a une clé primaire {id_car, id_driver} composée des deux attributs id_car et id_driver. Une table peut en outre avoir des clés alternatives (contraintes d’unicité).


    Citation Envoyé par matheous Voir le message
    si je laisse le MCD tel quel, un chauffeur ne peut conduire qu'une seule voiture ET une voiture ne peut être conduit que par un seul et unique chauffeur.
    Faux. Etant composée de deux attributs, la clé primaire de la table TO_DRIVE peut prendre par exemple les valeurs suivantes :

    Fernand    voiture 1
    Fernand    voiture 2
    Fernand    voiture 3
    Raoul      voiture 1
    Raoul      voiture 4
    Paul       voiture 1
    Paul       voiture 3
    

    Citation Envoyé par matheous Voir le message
    Cependant, un chauffeur peut en conduire plusieurs par jours et une voiture conduite par plusieurs chauffeurs (d'où mes DateTime_Departure et DateTime_Arrival).
    Selon votre MCD, un chauffeur donné ne peut conduire une voiture donnée qu’une seule fois, ce qui est bien peu...

    L’usage est de définir une entité-type DATE, ou HORAIRE si l’heure est à prendre en compte en plus de la date (format de type intervalle du genre [yyyy-mm-jj-hh-mn-ss:yyyy-mm-jj-hh-mn-ss]), entité-type dont on demande qu’elle ne fasse pas l’objet d’une table lors de la génération du MLD, car elle n’a pas d’intérêt en soi (noter que Looping met le nom de l’entité-type entre parenthèses quand on lui a fait savoir qu’il n’y a pas de table à générer). Par contre, cette entité-type, disons HORAIRE participe à une contrainte d’intégrité fonctionnelle, en abrégé CIF (voyez Ingénierie des systèmes d'information : Merise deuxième génération (4e édition, 2001), page 115, figure 7.21) :

    Nom : matheous_chauffeurs_CIF_unique.png
Affichages : 1622
Taille : 10,1 Ko

    Ce qui se lit :

    Au cours d’un l’intervalle de temps donné, un chauffeur ne conduit qu’une seule voiture.

    MLD correspondant produit par Looping :

    CHAUFFEUR = (chauffeurId, chauffeurNom, chauffeurTel);
    VOITURE = (voitureId, voitureMarque, voitureModele);
    CONDUIRE = (#chauffeurId, Intervalle, #voitureId);

    Ainsi, la table CONDUIRE a pour clé primaire la paire {chauffeurId, Intervalle}.

    Pour des raisons évidentes de symétrie, on est conduit à mettre en oeuvre une seconde CIF, pour respecter la règle suivante :

    Au cours d’un l’intervalle de temps donné, une voiture n’est conduite que par un seul chauffeur.

    MCD enrichi :

    Nom : matheous_chauffeurs_CIF_double.png
Affichages : 1584
Taille : 13,4 Ko

    Mais Looping ne génère pas la clé alternative attendue : {voitureId, Intervalle}. On peut pallier en lui demandant d’ajouter la clé alternative dans le code SQL :

    Nom : matheous_chauffeurs_CIF_regle.png
Affichages : 1656
Taille : 15,2 Ko



    Mais tout ceci est insuffisant, car il faudra s’assurer que les intervalles de conduite des chauffeurs et les intervalles de conduite des voitures sont cohérents (problème du chevauchement des intervalles)... Il faudra à cet effet développer une assertion (cas de la norme SQL) ou un trigger dans le cas des SGBD SQL (au fait, quel est le vôtre ?)


    Citation Envoyé par matheous Voir le message
    Faut-il rajouter un id_course dans la table "To drive" ? Ou créer vraiment une entité "Course" à la place ? Quelle différence ?
    Vu ce qui précède, tout ceci est vain. Il faut commencer par créer les clés candidates {chauffeurId, Intervalle} et {voitureId, Intervalle} de la table CONDUIRE, puis développer un trigger de contrôle des recouvrements des intervalles.

     
    (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
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Août 2009
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par fsmrel Voir le message

    Mais tout ceci est insuffisant, car il faudra s’assurer que les intervalles de conduite des chauffeurs et les intervalles de conduite des voitures sont cohérents (problème du chevauchement des intervalles)... Il faudra à cet effet développer une assertion (cas de la norme SQL) ou un trigger dans le cas des SGBD SQL (au fait, quel est le vôtre ?)
    Merci pour ta réponse rapide. Le SGBD sera MySQL.

    Citation Envoyé par fsmrel Voir le message

    Vu ce qui précède, tout ceci est vain. Il faut commencer par créer les clés candidates {chauffeurId, Intervalle} et {voitureId, Intervalle} de la table CONDUIRE, puis développer un trigger de contrôle des recouvrements des intervalles.
    Du coup, avec le format donnée pour Intervalle, je stocke ça dans une chaîne au niveau du SGBD (cette chaine contiendra le dateheureDebut et le dateheureFin) ?

    Etant débutant dans le MCD, j'avais vaguement entendu parler des CIF mais plus trop de souvenirs de son utilisation.
    Quand tu dis, trigger de contrôle de recouvrement, peux-tu me dire en quoi cela consisterait ?

    Avant ta réponse, j'ai continué le MCD et en fait, j'en étais arrivé à une entité COURSE (qui remplacerait l'entité CONDUIRE dans ton MCD).
    Cette entité COURSE serait donc composée de sa clé primaire {id_chauffeur,id_course,id_voiture}.

    A l'intérieur de l'entité, j'aurai mis 2 attributs (DateHeure_Depart et DateHeure_Arrivée).

    Ensuite, pour vérifier dans l'application les voitures disponibles à un instant T, j'aurai géré cela en programmation mais pas sur que ce soit la bonne solution...

    En réalité, le chauffeur ne pourra pas récupérer une voiture déjà prise. Cependant, ayant des voitures de modèles identiques (attribut plaque_immatriculation à rajouter dans l'entité Voiture), j'aimerai bien géré ces indisponibilités correctement pour éviter les erreurs de choix de véhicules.

    D'autre part, le chauffeur aura un questionnaire à remplir concernant l'état du véhicule récupéré. Comment stocker les données de cet état ?
    J'avais pensé a stocker ces données dans l'entité COURSE ? Ce qui me permet ensuite de faire facilement des requêtes pour récupérer les différents états signalés sur une voiture donnée et une journée donnée.

  4. #4
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    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 133
    Points : 38 555
    Points
    38 555
    Billets dans le blog
    9
    Par défaut
    Bonjour,

    Citation Envoyé par matheous Voir le message
    Mu coup, avec le format donnée pour Intervalle, je stocke ça dans une chaîne au niveau du SGBD (cette chaine contiendra le dateheureDebut et le dateheureFin) ?
    Jamais malheureux !
    Stocker des données temporelles dans une chaîne de caractères est la source de tous les maux :
    - l'encombrement est supérieur à celui de données de type date
    - la validité est à contrôler par traitement, sans garantie absolue du contenu, contrairement à des attributs de type date/date-time/timestamp fiabilisés par le SGBD.
    - selon le format de stockage et les séparateurs, les tris sont erronés
    - il est impossible d'appliquer toutes les fonctions liées au type date sauf en passant par des conversions de type, peu performantes et qui peuvent planter puisque le contenu n'est pas fiabilisé par le SGBD.

    Un intervalle c'est au choix une date/heure de début et de fin ou une date/heure de début et une durée



    Citation Envoyé par matheous Voir le message
    Quand tu dis, trigger de contrôle de recouvrement, peux-tu me dire en quoi cela consisterait ?
    Fonctionnellement : si le chauffeur C1 conduit le véhicule V1 de 10h00 à 14h00 alors le chauffeur C2 ne peut le conduire qu'avant 10h00 ou qu'après 14h00
    Techniquement : le trigger est un composant base de données qui se déclenche avant, à la place ou après un ordre SQL de mise à jour. Ce composant contient un script SQL à exécuter.
    à noter : MySQL ne connait que les triggers avant et après.


    Citation Envoyé par matheous Voir le message
    Avant ta réponse, j'ai continué le MCD et en fait, j'en étais arrivé à une entité COURSE (qui remplacerait l'entité CONDUIRE dans ton MCD).
    Cette entité COURSE serait donc composée de sa clé primaire {id_chauffeur,id_course,id_voiture}.
    Non !
    "conduire" dans le MCD proposé par FSMREL n'est pas une entité-type, mais une association !
    La table qui en résulte n'a donc pas d'identifiant propre, mais hérite des identifiants qui concourent à cette association.
    Soit, comme l'a mentionné FSMREL, id_voiture, id_chauffeur, id_intervalle



    Citation Envoyé par matheous Voir le message
    Ensuite, pour vérifier dans l'application les voitures disponibles à un instant T, j'aurai géré cela en programmation mais pas sur que ce soit la bonne solution...
    Mauvaise solution, seul le SGBD peut garantir que la voiture disponible au moment de la vérification est toujours disponible au moment de la validation de la réservation.
    Aucun langage aussi évolué soit il ne sait gérer les accès concurrents en environnement multi-utilisateurs et multi-thread avec la même sécurité qu'un SGBD-R

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

    Il est possible de renommer l’association CONDUIRE en COURSE :allons-y.

    A propos du type INTERVAL : MySQL ne le propose pas, il va donc falloir en passer par un attribut date/heure de début de course (de type DATETIME) et un attribut date/heure de fin.

    MCD :

    Nom : matheous_chauffeurs_mcd_datetime.png
Affichages : 1543
Taille : 19,8 Ko


    Problèmes de recouvrement :

    Dans un 1er temps, il s’agit d’avoir en tête les problèmes de recouvrement/bilocation, qui dans le cas de MySQL sont à traiter par un trigger attaché à la table COURSE. La programmation du trigger est à réaliser en tenant compte des scénarios suivants :

    Nom : matheous_chauffeurs_Au_temps_T_un_seul_chauffeur_par_vehicule.png
Affichages : 1337
Taille : 15,1 Ko


    Nom : matheous_chauffeurs_Au_temps_T_un_seul_vehicule_par_chauffeur(bilocation).png
Affichages : 1358
Taille : 14,8 Ko

    Si vous avez des difficultés pour programmer le trigger, on essaiera de vous aider (pour ma part, il faudra d’abord que je réinstalle MySQL dont je ne me sers plus depuis un bon moment...)


     

    ________________________
    (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
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Août 2009
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    J'ai déjà développé des triggers c'est pas le plus compliqué en soit.
    J'ai une autre solution en tête, mais je ne sais pas si elle est viable...

    Nom : Capture.PNG
Affichages : 1439
Taille : 16,0 Ko

    J'ai créé une entité "Course" avec une date heure de départ et une date heure de fin.
    Cette entité, de part ses relations, aura les identifiants des 2 autres (id_voiture et id_chauffeur).

    Grâce à cette méthode, je serai capable de dire qui conduisait telle voiture à telle heure, ou par qui telle voiture a été conduit.
    Ou encore, qui était sur la route entre telle tranche horaire.

    Une autre statistique intéressante, le temps de trajet de chacun des chauffeurs sur un jour, un mois ou une année.

    Enfin, concernant la disponibilité des véhicules, par une jointure externe entre la table Voiture et Course, je serai capable d'afficher les voitures disponibles.
    Si je vais jusqu’au code SQL ("cars" pour voitures, "fares" pour course)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM cars c 
    LEFT JOIN fares f ON f.id_car = c.id_car
    WHERE (f.date_departure IS NOT NULL AND f.date_arrival IS NOT NULL) OR (f.id_fare IS NULL)
    (Il y aura certainement un SELECT DISTINCT a faire pour ne pas se retrouver avec des doublons).

    Q1. Normalement, cette requête, à l'instant T ou elle est demandée, devrait me renvoyer la liste des voitures disponibles ?
    - celles qui ont une dateheure de début et de fin (la course est considérée comme terminée)
    - et celles qui n'ont pas de id_course (dans le cas ou elle vient d'arriver dans le stock et elle n'a pas réalisée de trajet)

    Je me dis que d'après votre œil expert, je suis loin de quelque chose de viable mais bon, je propose

    Et dernière question, le chauffeur aura des données à renseigner à chaque début de course (d'où l'entité Cars_data).

    Or, j'aimerai savoir quel chauffeur à renseigner la ligne des données. Faut-il juste mettre une clé étrangère id_chauffeur dans l'entité cars_data ?
    Ou je dois vraiment la relier avec une autre via une association ?
    Q2. D'ordre plus générale, est-ce que "ca se fait" de renseigner une clé étrangère d'une table sans association ?

  7. #7
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    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 133
    Points : 38 555
    Points
    38 555
    Billets dans le blog
    9
    Par défaut
    bonjour

    Ce modèle n'interdit pas qu'un même conducteur conduise plusieurs voitures au même moment ni qu'une même voiture soit conduite par plusieurs conducteurs au même moment

    Et une remarque d'ordre général : vous communiquez vos règles en français, mais votre modèle comporte des noms d'entité-type, de relation et d'attributs en anglais.
    Ça ne facilite pas la discussion et est-ce utile ?
    Si votre projet est strictement francophone, simplifiez vous la vie en utilisant des termes francophones.
    Si votre projet est international, la langue de Shakespeare s'impose, mais en ce cas, établissez la correspondance entre les désignations utilisées dans le discours en français et les objets du modèle qui sont en anglais

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Août 2009
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par escartefigue Voir le message
    bonjour

    Ce modèle n'interdit pas qu'un même conducteur conduise plusieurs voitures au même moment ni qu'une même voiture soit conduite par plusieurs conducteurs au même moment

    Et une remarque d'ordre général : vous communiquez vos règles en français, mais votre modèle comporte des noms d'entité-type, de relation et d'attributs en anglais.
    Ça ne facilite pas la discussion et est-ce utile ?
    Si votre projet est strictement francophone, simplifiez vous la vie en utilisant des termes francophones.
    Si votre projet est international, la langue de Shakespeare s'impose, mais en ce cas, établissez la correspondance entre les désignations utilisées dans le discours en français et les objets du modèle qui sont en anglais
    Le projet est en anglais, je vais utiliser les entités en anglais

    Disons que l'intervalle me parait compliqué à gérer...

    Au niveau base de données, oui c'est possible qu'un conducteur conduit plusieurs voitures en même temps... Mais autant bien gérer les enregistrements en programmation , à moins que vous m'aidiez un peu à programmer le trigger car je ne vous cache pas que cela est encore flou dans ma tête.

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

    matheous,

    Manifestement les CIF vous laissent de marbre, vous les ignorez superbement, soit. Mais au moins utilisez le minimum syndical en demandant à Looping d’enrichir le code SQL avec les contraintes d’unicité : cliquez sur l’outil Règle puis à l’aide de l’outil Lien établissez un lien entre et la règle qui vient d’être créée.

    Nom : matheous_chauffeurs_ent_course.png
Affichages : 1415
Taille : 20,1 Ko

    Ceci fait, créez le trigger contrôlant les recouvrements : à défaut je ne donne pas cher de votre base de données quand elle sera opérationnelle et pourira tout doucement, et ce n’est pas escartefigue qui me contredira...



    Citation Envoyé par matheous Voir le message
    le chauffeur aura des données à renseigner à chaque début de course (d'où l'entité Cars_data).
    Le chauffeur est partie prenante dans cette affaire d’où le prédicat :

    (P1) - Lors de la course C débutant au moment T, le chauffeur A enregistre la consommation d’essence du véhicule V

    Or selon votre modèle, ce prédicat est réduit à :

    (P2) - La consommation d’essence du véhicule V est enregistrée

    On ne sait donc ni quel chauffeur est concerné ni le moment correspondant à cette consommation...

    Pour être en phase avec le prédicat P1, les attributs FuelLevel et Mileage doivent migrer vers une entité-type (ou une association) à laquelle participent le chauffeur, le véhicule et la date de début de course...


    Citation Envoyé par matheous Voir le message
    celles qui ont une dateheure de début et de fin (la course est considérée comme terminée)
    Evitez l’intrusion de NULL, l’inhibiteur des optimiseurs des SGBDR et qui invalide les théorèmes de la théorie relationnelle ; si une course est en cours, considérez qu’elle se termine à l’infini, disons à l’instant '9999-12-31 23:59:59''.


    Citation Envoyé par matheous Voir le message
    Il y aura certainement un SELECT DISTINCT
    Avant de vous plonger dans la programmation des requêtes SQL attendez que votre MCD et votre MLD soient corrects et stabilisés.


    Vous écrivez en dernier lieu :

    Citation Envoyé par matheous Voir le message
    Au niveau base de données, oui c'est possible qu'un conducteur conduit plusieurs voitures en même temps
    Vous dérivez vers un univers quantique, ça craint...


     
    (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.

  10. #10
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 133
    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 133
    Points : 38 555
    Points
    38 555
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par fsmrel Voir le message
    Ceci fait, créez le trigger contrôlant les recouvrements : à défaut je ne donne pas cher de votre base de données quand elle sera opérationnelle et pourira tout doucement, et ce n’est pas escartefigue qui me contredira...
    Au contraire : je plussoie avec énergie



    Citation Envoyé par fsmrel Voir le message
    Vous dérivez vers un univers quantique, ça craint...
    Ou alors celui du spectacle et des acrobaties

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Août 2009
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    Citation Envoyé par fsmrel Voir le message
    Bonsoir,

    matheous,

    Manifestement les CIF vous laissent de marbre, vous les ignorez superbement, soit. Mais au moins utilisez le minimum syndical en demandant à Looping d’enrichir le code SQL avec les contraintes d’unicité : cliquez sur l’outil Règle puis à l’aide de l’outil Lien établissez un lien entre et la règle qui vient d’être créée.
     
    Je ne les ignore pas... Bien au contraire, je suis la pour créer un MCD fiable et non sur 3 pattes...

    J'ai du mal a voir la partie CIF et le trigger de recouvrement.

    J'ai besoin d'exemples concrets (des données a l'intérieur des entités) pour comprendre leurs rôles.

    Le MCD reste en quelque sorte pour moi de la théorie... J'ai du mal a comprendre sans quelque chose de concret.

    Pour en revenir a vos conseils, j'ai bien compris qu'il fallait partir sur cette méthode et c'est pour ça que je demande des détails pour pouvoir au mieux l'utiliser.

    Citation Envoyé par fsmrel Voir le message
    Pour être en phase avec le prédicat P1, les attributs FuelLevel et Mileage doivent migrer vers une entité-type (ou une association) à laquelle participent le chauffeur, le véhicule et la date de début de course...
     
    Donc l'entité-type Cars_Data doit être associée avec la table Fares ?
    Auquel cas, je saurai donc quel chauffeur a renseigné ces données et a quel moment et pour quelle course.

  12. #12
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 001
    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 001
    Points : 30 905
    Points
    30 905
    Billets dans le blog
    16
    Par défaut
    Bonsoir,


    Citation Envoyé par matheous Voir le message
    Le MCD reste en quelque sorte pour moi de la théorie... J'ai du mal a comprendre sans quelque chose de concret.
    Un MCD est un modèle, il n’est donc pas de la théorie. Depuis plus de trente ans que j’utilise des MCD, je m’en suis beaucoup servi chez mes clients, comme support de communication auprès de la maîtrise d’oeuvre, voire de la maîtrise d’ouvrage, gens comprenant vite la méthode de construction.

    Le MCD a un côté bande dessinée indéniable, mais il n’en demeure pas moins que le MLD puis le code SQL (les create table) en sont la conséquence et donc il vaut mieux ne pas se fourvoyer à ce stade. De même le MCD est lui-même la conséquence des règles de gestion qui doivent évidemment être formulées de façon exhaustive et rigoureuse.

    Vous avez du mal à comprendre sans quelque chose de concret : d’accord, on va mettre les mains dans le cambouis avec des exemples.

    Partons du code SQL suivant :

    CREATE TABLE CHAUFFEUR
    (
            chauffeurId          INTEGER        NOT NULL
          , chauffeurMatricule   VARCHAR(12)    NOT NULL
          , chauffeurNom         VARCHAR(48)    NOT NULL
          , chauffeurTel         VARCHAR(20)    NOT NULL DEFAULT ' '
      , CONSTRAINT CHAUFFEUR_PK PRIMARY KEY (chauffeurId)
      , CONSTRAINT CHAUFFEUR_AK UNIQUE (chauffeurMatricule)
    );
    
    CREATE TABLE VOITURE
    (
            voitureId            INTEGER        NOT NULL
          , voitureImmat         VARCHAR(12)    NOT NULL
          , voitureMarque        VARCHAR(24)    NOT NULL 
          , voitureModele        VARCHAR(48)    NOT NULL DEFAULT ' '
        , CONSTRAINT VOITURE_PK PRIMARY KEY (voitureId)
        , CONSTRAINT VOITURE_AK UNIQUE (voitureImmat)
    );
    
    CREATE TABLE COURSE
    (
            voitureId            INTEGER        NOT NULL
          , chauffeurId          INTEGER        NOT NULL
          , dateHeureDebut       DATETIME       NOT NULL 
          , dateHeureFin         DATETIME       NOT NULL DEFAULT '9999-12-31 23:59:59'
          , CONSTRAINT COURSE_AK1 UNIQUE (voitureId, dateHeureDebut)
          , CONSTRAINT COURSE_AK2 UNIQUE (chauffeurId, dateHeureDebut)
        , CONSTRAINT COURSE_AK3 UNIQUE (voitureId, dateHeureFin)
        , CONSTRAINT COURSE_AK4 UNIQUE (chauffeurId, dateHeureFin)
        , CONSTRAINT COURSE_VOITURE_FK FOREIGN KEY (voitureId) 
              REFERENCES VOITURE (voitureId)
        , CONSTRAINT COURSE_CHAUFFEUR_FK FOREIGN KEY (chauffeurId) 
              REFERENCES CHAUFFEUR (chauffeurId)
        , CONSTRAINT COURSE_DATE_CHK CHECK (dateHeureDebut < dateHeureFin)
    );
    

    Un trigger pour les inserts dans la table COURSE :

     DROP TRIGGER IF EXISTS COURSE_INSERT ;
    
     delimiter GO
     
    CREATE TRIGGER COURSE_INSERT BEFORE INSERT ON COURSE 
    FOR EACH ROW
        BEGIN
             set @pNew = NEW.chauffeurId ;
             set @vNew = NEW.voitureId ;
             set @debutNew = NEW.dateHeureDebut ;
             set @finNew = NEW.dateHeureFin ;
             set @engueulade1 = ' : à T, une voiture n’est conduite que par un seul chauffeur.' ;   
             set @engueulade2 = ' : à T, un chauffeur ne conduit qu’une seule voiture.' ;   
    
    /* -- ------------------------------------------------------        
    --     Au cours d’un l’intervalle de temps donné, 
    --     une voiture n’est conduite que par un seul chauffeur
    */ -- ------------------------------------------------------
             
             set @N = (SELECT  COUNT(*)
                       FROM   COURSE 
                       WHERE  voitureId = @vNew AND dateHeureDebut <>  @debutNew
            IF @N > 0 THEN
                SET @erreur = CONCAT('voitureId = ', @vNew, ' ; chauffeurId = ', @pNew, ' ; début = ', @debutNew,  @engueulade1) ;
                SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = @erreur ;
            END IF ;
    /* -- ------------------------------------------------------        
    --     Au cours d’un l’intervalle de temps donné,  
    --     un chauffeur ne conduit qu’une seule voiture
    */ -- ------------------------------------------------------
             set @N = (SELECT  COUNT(*)
                       FROM   COURSE 
                       WHERE  chauffeurId = @pNew AND dateHeureDebut <>  @debutNew
            IF @N > 0 THEN
                SET @erreur = CONCAT('voitureId = ', @vNew, ' ; chauffeurId = ', @pNew, ' ; début = ', @debutNew,  @engueulade2) ;
                SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = @erreur ;
            END IF ;        
        END
    
    GO
    
    delimiter ;
    
    Si les requêtes SQL ne sont pas valides, escartefigue ne manquera pas de les corriger, car il ne laisse rien passer…


    Un début de jeu d’essai, dans lequel le recouvrement de dates est omniprésent :

    INSERT INTO CHAUFFEUR (chauffeurId, chauffeurMatricule, chauffeurNom)
    VALUES 
        (1, 'Fernand', 'Fernand Naudin'),  (2, 'Raoul', 'Raoul Volfoni'),  (3, 'Paul', 'Paul Volfoni')
    ;
    SELECT * FROM CHAUFFEUR ;
    
    INSERT INTO VOITURE (voitureId, voitureImmat, voitureMarque)
    VALUES 
        (1, '1 ZAA 75', 'Peugeot'),  (2, '2 ZBB 75', 'Peugeot')
    ;
    SELECT * FROM VOITURE ;
    
    INSERT INTO COURSE (voitureId, chauffeurId, dateHeureDebut, dateHeureFin)
    VALUES 
        (1, 1, '2019-02-01 12:00:00', '2019-07-02 12:30:00')
      , (1, 2, '2019-02-01 12:02:00', '2019-02-01 12:25:00')
    
      , (2, 1, '2019-02-01 12:05', '2019-07-02 12:35')
      , (2, 2, '2019-02-01 12:08', '2019-02-01 12:15')
      , (2, 3, '2019-02-01 12:09', '2019-02-01 12:23')
    ;
    
    SELECT * FROM COURSE ;

    Citation Envoyé par matheous Voir le message
    Donc l'entité-type Cars_Data doit être associée avec la table Fares ?
    Je reprends ce que vous aviez écrit auparavant :

    Citation Envoyé par matheous Voir le message
    le chauffeur aura des données à renseigner à chaque début de course (d'où l'entité Cars_data).
    Dans la mesure où le chauffeur fournira impérativement ces données concernant la voiture impliquée dans la course, Cars_data devient inutile, c’est la table COURSE qui devra héberger ces données.


    Quand les choses seront stabilisées, on pourra remonter sur le pont et revenir sur le concept de CIF.
     
    (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.

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    97
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Août 2009
    Messages : 97
    Points : 59
    Points
    59
    Par défaut
    C'est peut-être idiot, mais dès que tu me présentes du code, je vois beaucoup mieux ou tu souhaites en venir.

    J'ai bien assimilé toutes les contraintes de chacune des tables, ainsi que le trigger avant insertion.

    Ceci me permettra donc de ne pas "écrire de conneries" dans la BDD.
    Chaque contraintes et clés étrangères a pour but d'avoir une BDD propre à chaque insertion (c'est le but du MCD en même temps...).

    Enfin, le trigger avant insertion permet de contrôler que le chauffeur (new.idchauffeur) n'est pas en train de conduire une autre voiture ET que la voiture (new.idvoiture) n'est pas conduit par un autre.

    Ok jusque là, je n'ai rien a rajouter :$

  14. #14
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 001
    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 001
    Points : 30 905
    Points
    30 905
    Billets dans le blog
    16
    Par défaut
    Bonsoir matheous,


    Pour éviter de mauvaises surprises lors de mises à jour concurrentes, il est préférable de remplacer BEFORE par AFTER pour le trigger COURSE_INSERT :

    CREATE TRIGGER COURSE_INSERT AFTER INSERT ON COURSE

     
    (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.

  15. #15
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 001
    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 001
    Points : 30 905
    Points
    30 905
    Billets dans le blog
    16
    Par défaut
    Aîe ! P... de copier/coller... En relisant le code du trigger, je constate qu’a sauté le principal, à savoir le test de recouvrement :

    AND NOT (@debutNew >= dateHeureFin OR @finNew <= dateHeureDebut)

    Voici donc une version moins incorrecte du trigger :

    DROP TRIGGER IF EXISTS COURSE_INSERT ;
    
    delimiter GO
    
    CREATE TRIGGER COURSE_INSERT AFTER INSERT ON COURSE 
    FOR EACH ROW
        BEGIN
             set @pNew = NEW.chauffeurId ;
             set @vNew = NEW.voitureId ;
             set @debutNew = NEW.dateHeureDebut ;
             set @finNew = NEW.dateHeureFin ;
             set @engueulade1 = ' : à T, une voiture n’est conduite que par un seul chauffeur.' ;   
             set @engueulade2 = ' : à T, un chauffeur ne conduit qu’une seule voiture.' ;   
    
     /* -- ------------------------------------------------------        
            
    --     Au cours d’un l’intervalle de temps donné, 
    --     une voiture n’est conduite que par un seul chauffeur
    */ -- ------------------------------------------------------
             
             set @N = (SELECT  COUNT(*)
                       FROM   COURSE 
                       WHERE  voitureId = @vNew AND dateHeureDebut <>  @debutNew
                       AND NOT (@debutNew >= dateHeureFin  OR  @finNew <= dateHeureDebut)
                      ) ;
            IF @N > 0 THEN
                SET @erreur = CONCAT('voitureId = ', @vNew, ' ; chauffeurId = ', @pNew, ' ; début = ', @debutNew,  @engueulade1) ;
                SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = @erreur ;
            END IF ;
    /* -- ------------------------------------------------------        
    --     Au cours d’un l’intervalle de temps donné,  
    --     un chauffeur ne conduit qu’une seule voiture
    */ -- ------------------------------------------------------
             set @N = (SELECT  COUNT(*)
                       FROM   COURSE 
                       WHERE  chauffeurId = @pNew AND dateHeureDebut <>  @debutNew
                       AND NOT (@debutNew >= dateHeureFin  OR  @finNew <= dateHeureDebut)
                      ) ;
            IF @N > 0 THEN
                SET @erreur = CONCAT('voitureId = ', @vNew, ' ; chauffeurId = ', @pNew, ' ; début = ', @debutNew,  @engueulade2) ;
                SIGNAL SQLSTATE '45001' SET MESSAGE_TEXT = @erreur ;
            END IF ;
            
        END
    
    GO
    
    delimiter ;
    
    Continuons à vérifier !

     
    (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.

  16. #16
    Expert éminent sénior
    Avatar de fsmrel
    Homme Profil pro
    Spécialiste en bases de données
    Inscrit en
    Septembre 2006
    Messages
    8 001
    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 001
    Points : 30 905
    Points
    30 905
    Billets dans le blog
    16
    Par défaut
    Bonsoir,


    Concernant les contrôles de recouvrement, le trigger affecté aux updates est le même que celui qui est affecté aux inserts. Il suffit donc de copier/coller ce dernier, en remplaçant la ligne :

    CREATE TRIGGER COURSE_INSERT AFTER INSERT ON COURSE

    Par celle-ci :

    CREATE TRIGGER COURSE_UPDATE AFTER UPDATE ON COURSE


    Un jeu d’essai contenant des inserts et des updates :

    -- -----------------------------------------------------
    -- conditions initiales
    -- -----------------------------------------------------
    
    DELETE FROM COURSE ;
    DELETE FROM CHAUFFEUR ;
    DELETE FROM VOITURE ;
    
    -- -----------------------------------------------------
    -- quelques inserts
    -- -----------------------------------------------------
    
    INSERT INTO CHAUFFEUR (chauffeurId, chauffeurMatricule, chauffeurNom)
    VALUES 
        (1, 'Fernand', 'Fernand Naudin'),  (2, 'Raoul', 'Raoul Volfoni'),  (3, 'Paul', 'Paul Volfoni')
    ;
    
    INSERT INTO VOITURE (voitureId, voitureImmat, voitureMarque)
    VALUES 
        (1, '1 ZAA 75', 'Peugeot'),  (2, '2 ZBB 75', 'Peugeot')
    ;
    
    INSERT INTO COURSE (voitureId, chauffeurId, dateHeureDebut, dateHeureFin)
    VALUES
        (1, 1, '2019-02-01 12:00:00', '2019-02-01 12:30:00') -- valide
      , (1, 2, '2019-02-01 12:30:00', '2019-02-01 14:25:00') -- valide   
    ;
    
    INSERT INTO COURSE (voitureId, chauffeurId, dateHeureDebut, dateHeureFin)
    VALUES
        (2, 1, '2019-02-01 12:30:00', '2019-02-01 15:00:00')   -- valide
    ;
    INSERT INTO COURSE (voitureId, chauffeurId, dateHeureDebut)
    VALUES    
       (2, 1, '2019-02-01 15:00:00')   -- valide, fin par défaut
    ;
    
    SELECT *, 'Les inserts' FROM COURSE ORDER BY voitureId, dateHeureDebut ;
    
    -- -----------------------------------------------------
    -- quelques updates de la table COURSE
    -- -----------------------------------------------------
    
    UPDATE COURSE  -- valide
        SET dateHeureDebut = '2019-02-01 12:35:00'
        WHERE voitureId = 1 and dateHeureDebut = '2019-02-01 12:30:00'    
    ;
    SELECT * FROM COURSE ORDER BY voitureId, dateHeureDebut ;
    
    UPDATE COURSE  -- valide
        SET dateHeureFin = '2019-02-01 13:35:00'
        WHERE voitureId = 1 and dateHeureDebut = '2019-02-01 12:35:00'    
    ;
    SELECT * FROM COURSE ORDER BY voitureId, dateHeureDebut ;
    
    UPDATE COURSE  -- valide
        SET dateHeureFin = '2019-02-01 13:35:00'
        WHERE voitureId = 1 and dateHeureDebut = '2019-02-01 12:35:00'    
    ;
    SELECT * FROM COURSE ORDER BY voitureId, dateHeureDebut ;
    
    UPDATE COURSE  -- recouvrement (à T, v1 conduite par c1 et c2)
        SET dateHeureFin = '2019-02-01 13:32:00'
        WHERE voitureId = 1 and dateHeureDebut = '2019-02-01 12:00:00'    
    ;
    SELECT * FROM COURSE ORDER BY voitureId, dateHeureDebut ;
    
    UPDATE COURSE  -- recouvrement (à T, c1 conduit v1 et v2)
        SET dateHeureDebut = '2019-02-01 12:20:00'
        WHERE voitureId = 2 and dateHeureDebut = '2019-02-01 12:30:00'    
    ;
    SELECT * FROM COURSE ORDER BY voitureId, dateHeureDebut ;
    
    Au résultat :

     
    voitureId    chauffeurId    dateHeureDebut            dateHeureFin
    
    1            1              '2019-02-01 12:00:00'     '2019-02-01 13:32:00'
    1            2              '2019-02-01 12:35:00'     '2019-02-01 13:35:00'
    2            1              '2019-02-01 12:20:00'     '2019-02-01 15:00:00'
    2            1              '2019-02-01 15:00:00'     '9999-12-31 23:59:59'
    
    A vous de jouer...

     
    (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.

  17. #17
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 761
    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 761
    Points : 52 547
    Points
    52 547
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par escartefigue Voir le message
    ...
    Techniquement : le trigger est un composant base de données qui se déclenche avant, à la place ou après un ordre SQL de mise à jour. Ce composant contient un script SQL à exécuter.
    à noter : MySQL ne connait que les triggers avant et après.
    Et pire les déclencheurs MySQL n'étant pas ensemblistes, le contrôle de cohérence de superposition des intervalles est impossible !

    Tu connais pourquoi maintenant....

    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/ * * * * *

Discussions similaires

  1. Réponses: 4
    Dernier message: 07/08/2017, 10h39
  2. Réponses: 44
    Dernier message: 28/07/2017, 12h36
  3. [EJB2.1 Entity] [CMR] Relation One to Many
    Par hamed dans le forum Java EE
    Réponses: 2
    Dernier message: 31/12/2003, 14h26
  4. Réponses: 2
    Dernier message: 26/09/2003, 15h54
  5. Problème avec mes tables de relation...
    Par mmike dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 02/06/2003, 15h16

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