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

Requêtes MySQL Discussion :

Jointure intervalle de date


Sujet :

Requêtes MySQL

  1. #1
    Futur Membre du Club
    Femme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2023
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2023
    Messages : 6
    Points : 6
    Points
    6
    Par défaut Jointure intervalle de date
    Bonjour à tous,

    Je me permets de vous soumettre un cas de jointure qui me pose problème.
    J’ai une table d’utilisateur qui se présente ainsi :

    id |taille| taille_depuis|poids| poids_depuis
    1 | 176 | 2022-12-06 | 85 | 2022-09-15

    Les colonnes taille_depuis et poids_depuis représentent les dates auxquelles les colonnes taille et poids ont été modifiées.
    J’ai en plus 2 tables qui permettent l’historisation des changements de taille et du poids de mon utilisateur :
    taille_histo :
    idUser | taille | dateDebut | dateFin
    1 | 170 | 2022-03-09 | 2022-11-28
    1 | 175 | 2022-11-28 | 2022-12-06

    poids_histo :
    idUser | poids | dateDebut | dateFin
    1 | 80 | 2022-03-09 | 2022-09-15

    Mon problème est que maintenant j’ai besoin d’avoir l’évolution de l’IMC et que je n’arrive pas du tout à voir comment faire
    la jointure avec les intervalles de dates, en sachant que le résultat attendu est :
    idUser | IMC | dateDebut | dateFin
    1 | 27,7 | 2022-03-09 | 2022 -09-15
    1 | 29,4 | 2022-09-15 | 2022-11-28
    1 | 27,8 | 2022-11-28 | 2022-12-06
    1 | 27,4 | 2022-12-06 | 2023-01-17(date de la requête)

    Petite précision j’utilise MySQL 5.6.
    Merci d’avance pour votre aide.

  2. #2
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 801
    Points
    30 801
    Par défaut
    Bonjour,

    Qu'as-tu déjà testé comme requête(s) ?
    Où rencontres-tu un problème ?
    • Une erreur d'exécution ? Quel est le message associé ?
    • Un résultat erroné ? Quel est le résultat obtenu ? Le résultat attendu ? Avec quelles données ?
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  3. #3
    Futur Membre du Club
    Femme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2023
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2023
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Actuellement ma requête ressemble à cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SELECT T1.idUser, (T2.poids / (T1.taille * T1.taille)) AS IMC, T1.dateDebut, T2.dateFin
    FROM taille_histo as T1
        INNER JOIN poids_histo as T2
        ON T1.idUser = T2.idUser
        WHERE T1.dateDebut <= T2.dateDebut
        AND T1.dateFin >= T2.dateFin
    Ce qui me donne le résultat:
    idUser | IMC | dateDebut | dateFin
    1 | 27,7 | 2022-03-09 | 2022-09-15

    Le résultat attendu et les données sont dans mon 1er message.
    Mon problème est que je ne vois pas comment faire évoluer ma requête pour réussir à gérer les intervalles de dates.

  4. #4
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    Dans vos tables historiques, il est inutile de préciser la date de fin de vos intervalles de temps.
    Quand vous avez deux lignes, la première se termine quand la seconde commence.
    La date de début de la ligne suivante est en fait la date de fin de la ligne précédente.

    Un jeu d'essai complet aurait été bienvenue !

    Je ne comprends pas l'intérêt d'avoir deux tables, l'une pour le poids et l'autre pour la taille.
    Vous n'allez pas me dire que lors d'une consultation, on mesure le poids ou la taille mais pas les deux en même temps.
    J'ai supprimé vos tables "poids" et "taille" que j'ai remplacé par "mesure".
    Et comme par hasard, le problème d'appareiller vos dates se résout de lui-même.

    Vous vous compliquez l'existence ! Allez au plus simple.
    Code mysql : 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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    --------------
    START TRANSACTION
    --------------
     
    --------------
    DROP DATABASE IF EXISTS `base`
    --------------
     
    --------------
    CREATE DATABASE IF NOT EXISTS `base`
            DEFAULT CHARACTER SET `latin1`
            DEFAULT COLLATE       `latin1_general_ci`
    --------------
     
    --------------
    DROP TABLE IF EXISTS `personne`
    --------------
     
    --------------
    CREATE TABLE `personne`
    ( `id`        integer unsigned not null auto_increment primary key,
      `nom`       varchar(255)     not null,
      `prenom`    varchar(255)     not null
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `personne` (`nom`,`prenom`) values
      ('Nom Un','Prénom Un'),('Nom Deux','Prénom Deux')
    --------------
     
    --------------
    select * from `personne`
    --------------
     
    +----+-----------+-------------+
    | id | nom       | prenom      |
    +----+-----------+-------------+
    |  1 | Nom Un    | Prénom Un   |
    |  2 | Nom Deux  | Prénom Deux |
    +----+-----------+-------------+
    --------------
    DROP TABLE IF EXISTS `mesure`
    --------------
     
    --------------
    CREATE TABLE `mesure`
    ( `id`            integer unsigned not null auto_increment primary key,
      `taille`        decimal(5,2)     not null,
      `poids`         integer unsigned not null,
      `depuis`        date             not null,
      `personne_fk`   integer unsigned not null,
      CONSTRAINT `FK_01` FOREIGN KEY (`personne_fk`) REFERENCES `personne` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `mesure` (`taille`,`poids`,`depuis`,`personne_fk`) values
      (1.70, 80, '2022-03-09', 1),
      (1.70, 85, '2022-09-15', 1),
      (1.75, 85, '2022-11-28', 1),
      (1.76, 85, '2022-12-06', 1)
    --------------
     
    --------------
    select * from `mesure`
    --------------
     
    +----+--------+-------+------------+-------------+
    | id | taille | poids | depuis     | personne_fk |
    +----+--------+-------+------------+-------------+
    |  1 |   1.70 |    80 | 2022-03-09 |           1 |
    |  2 |   1.70 |    85 | 2022-09-15 |           1 |
    |  3 |   1.75 |    85 | 2022-11-28 |           1 |
    |  4 |   1.76 |    85 | 2022-12-06 |           1 |
    +----+--------+-------+------------+-------------+
    --------------
    select     t2.nom,
               t2.prenom,
               t1.poids,
               t1.taille,
               t1.depuis,
               cast(round(t1.poids / (t1.taille * t1.taille), 1) as decimal(5,1)) as IMC
     
          from `mesure` as t1
     
    inner join `personne` as t2
            on  t2.id = t1.personne_fk
     
      order by t2.nom, t1.depuis
    --------------
     
    +--------+-----------+-------+--------+------------+------+
    | nom    | prenom    | poids | taille | depuis     | IMC  |
    +--------+-----------+-------+--------+------------+------+
    | Nom Un | Prénom Un |    80 |   1.70 | 2022-03-09 | 27.7 |
    | Nom Un | Prénom Un |    85 |   1.70 | 2022-09-15 | 29.4 |
    | Nom Un | Prénom Un |    85 |   1.75 | 2022-11-28 | 27.8 |
    | Nom Un | Prénom Un |    85 |   1.76 | 2022-12-06 | 27.4 |
    +--------+-----------+-------+--------+------------+------+
    --------------
    COMMIT
    --------------
     
    Appuyez sur une touche pour continuer...

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  5. #5
    Futur Membre du Club
    Femme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2023
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2023
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Merci Artemus pour votre réponse !

    En fait oui ça arrive très souvent que la taille ou le poids soit vérifié mais pas les 2 en même temps.
    En tout cas je crois qu'effectivement je me suis compliqué un peu l'existence et ça m'a l'air beaucoup plus simple
    avec qu'une seule table.

  6. #6
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut Gorshka.

    Il faut bien faire la distinction entre ce que fait un conseiller où il n'est pas tenu de vérifier à chaque consultation la taille d'une personne et/ou son poids et ce que l'on va saisir dans la base de données.

    A priori, la taille ne varie pas énormément. Pourquoi ne pas la mettre dans la table "personne" ?
    La table "mesure" prendrait alors le nom de "poids" et vous ne stockeriez que les variations de celui-ci.

    Il ne vous reste plus qu'à mettre votre sujet en "résolu".

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  7. #7
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 801
    Points
    30 801
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    A priori, la taille ne varie pas énormément.
    Cette affirmation ne s'applique qu'à des personnes adultes... De 0 à 20 ans, la taille peut évoluer dans un rapport de 1 à 4 voire plus.
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  8. #8
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut Al_24.

    En écrivant cela, je pensais à des adultes.

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  9. #9
    Futur Membre du Club
    Femme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2023
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2023
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    A priori, la taille ne varie pas énormément. Pourquoi ne pas la mettre dans la table "personne" ?
    Ce n'est pas possible, j'ai besoin de pouvoir suivre l'évolution de la taille même si c'est de petites variations.

    J'ai suivi le conseil d'Artemus et je travaille qu'avec une seule table pour le poids et la taille.
    Merci à tous pour vos conseils.

  10. #10
    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 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Bonjour Gorshka

    Citation Envoyé par Gorshka Voir le message
    En fait oui ça arrive très souvent que la taille ou le poids soit vérifié mais pas les 2 en même temps.
    En tout cas je crois qu'effectivement je me suis compliqué un peu l'existence et ça m'a l'air beaucoup plus simple
    avec qu'une seule table.

    Citation Envoyé par Gorshka Voir le message
    J'ai suivi le conseil d'Artemus et je travaille qu'avec une seule table pour le poids et la taille.
    Ce faisant, à chaque fois que vous ne mesurerez que la masse ou que la taille, l'autre valeur sera marquée "null".
    Ce modèle de données n'est donc pas optimal, d'autres approches sont possibles en fonction du besoin, en particulier si d'autres mesures (rythme cardiaque, glycémie, albumine...) sont également faites à des échéances différentes.

  11. #11
    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 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Si l'on souhaite restituer les différentes mesures effectuées lors de la visite d'un patient, on peut modéliser comme suit :

    Au niveau conceptuel :

    Nom : MCD.png
Affichages : 62
Taille : 27,0 Ko

    Ce qui donne les tables suivantes :

    Nom : MLD.png
Affichages : 63
Taille : 33,9 Ko

    Et pour MySQL on obtient automatiquement le DDL suivant :

    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
    CREATE TABLE PE_personne(
       PE_ident INT AUTO_INCREMENT,
       PE_nom VARCHAR(50) NOT NULL,
       PE_prenom VARCHAR(50) NOT NULL,
       PE_ddn DATE NOT NULL,
       PRIMARY KEY(PE_ident)
    );
    CREATE TABLE YM_type_mesure(
       YM_ident INT AUTO_INCREMENT,
       YM_code CHAR(6) NOT NULL,
       YM_libelle VARCHAR(128) NOT NULL,
       YM_unite CHAR(5) NOT NULL,
       PRIMARY KEY(YM_ident),
       UNIQUE(YM_code)
    );
    CREATE TABLE VI_visite(
       PE_ident INT,
       VI_seq SMALLINT,
       VI_date DATE NOT NULL,
       PRIMARY KEY(PE_ident, VI_seq),
       FOREIGN KEY(PE_ident) REFERENCES PE_personne(PE_ident)
    );
    CREATE TABLE ME_mesure(
       PE_ident INT,
       VI_seq SMALLINT,
       ME_seq SMALLINT,
       ME_val DECIMAL(11,4) NOT NULL,
       YM_ident INT NOT NULL,
       PRIMARY KEY(PE_ident, VI_seq, ME_seq),
       FOREIGN KEY(PE_ident, VI_seq) REFERENCES VI_visite(PE_ident, VI_seq),
       FOREIGN KEY(YM_ident) REFERENCES YM_type_mesure(YM_ident)
    );

    Avec le jeu d'essai suivant :

    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
    insert into YM_type_mesure
          (YM_code, YM_libelle, YM_unite)
    values ('POIDS',  'poids en kilogrammes', 'kg')
         , ('TAILLE', 'taille en centimetres', 'cm')
         , ('GLYCEM', 'glycemie en grammes par litre', 'g/l')
    ;  
    insert into PE_personne
          (PE_nom, PE_prenom, PE_ddn)
    values ('martin', 'pauline', '1978-07-15')
         , ('abadie', 'remi', '1989-10-22')
         , ('lesage', 'odile', '1992-02-07')
         , ('dupont', 'yann', '1995-05-30')
    ;  
    insert into VI_visite
          (PE_ident, VI_seq, VI_date)
    values (1, 1, '2021-06-10')
         , (2, 1, '2021-06-10')
         , (1, 2, '2021-11-01')
         , (3, 1, '2021-12-18')
    ;
    insert into ME_mesure
          (PE_ident, VI_seq, ME_seq, ME_val, YM_ident)
    values (1, 1, 1, 55, 1)
         , (1, 1, 2, 167, 2)
         , (1, 1, 3, 0.82, 3)
         , (2, 1, 1, 181, 2)
         , (1, 2, 1, 56, 1)
         , (1, 2, 2, 0.79, 3)
         , (3, 1, 1, 163, 2)
         , (3, 1, 2, 58, 1)
    ;

    Et la requête suivante :

    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
    select PE_nom
         , PE_prenom 
         , PE_ddn  as date_naiss
         , VI_date as date_visite
         , ME1.ME_val as taille
         , ME2.ME_val as poids
         , ME3.ME_val as glycemie
    from PE_personne    PE
    left join VI_visite VI
        on VI.PE_ident = PE.PE_ident
    left join ME_mesure ME1  
        on ME1.PE_ident=VI.PE_ident
       and ME1.VI_seq  =VI.VI_seq
       and ME1.YM_ident=2 -- poids
    left join ME_mesure ME2  
        on ME2.PE_ident=VI.PE_ident
       and ME2.VI_seq  =VI.VI_seq
       and ME2.YM_ident=1 -- taille
    left join ME_mesure ME3  
        on ME3.PE_ident=VI.PE_ident
       and ME3.VI_seq  =VI.VI_seq  
       and ME3.YM_ident=3 -- glycemie
    order by PE_prenom 
           , PE_ddn  
           , VI_date


    on obtient le résultat qui suit :

    PE_nom PE_prenom date_naiss date_visite taille poids glycemie
    lesage odile 1992-02-07 2021-12-18 163.0000 58.0000 null
    martin pauline 1978-07-15 2021-06-10 167.0000 55.0000 0.8200
    martin pauline 1978-07-15 2021-11-01 null 56.0000 0.7900
    abadie remi 1989-10-22 2021-06-10 181.0000 null null
    dupont yann 1995-05-30 null null null null

    On sait directement quelles mesures et quelles valeurs ont été obtenues lors de chaque visite, ajouter une nouvelle mesure ne pose aucun souci, aucune structure de table ne sera à modifier, contrairement à un modèle tel que vous le proposez .

  12. #12
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    Deux méthodes, l'une en passant par des vues et l'autre par le COMMON TABLE EXPRESSIONS ou CTE.
    Code mysql : 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
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    --------------
    START TRANSACTION
    --------------
     
    --------------
    DROP DATABASE IF EXISTS `base`
    --------------
     
    --------------
    CREATE DATABASE IF NOT EXISTS `base`
            DEFAULT CHARACTER SET `latin1`
            DEFAULT COLLATE       `latin1_general_ci`
    --------------
     
    --------------
    DROP TABLE IF EXISTS `personne`
    --------------
     
    --------------
    CREATE TABLE `personne`
    ( `id`        integer unsigned not null auto_increment primary key,
      `nom`       varchar(255)     not null
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `personne` (`nom`) values
      ('Nom Un'),('Nom Deux'),('Nom Trois')
    --------------
     
    --------------
    select * from `personne`
    --------------
     
    +----+-----------+
    | id | nom       |
    +----+-----------+
    |  1 | Nom Un    |
    |  2 | Nom Deux  |
    |  3 | Nom Trois |
    +----+-----------+
    --------------
    DROP TABLE IF EXISTS `poids`
    --------------
     
    --------------
    CREATE TABLE `poids`
    ( `id`            integer unsigned not null auto_increment primary key,
      `mesure`        integer unsigned not null,
      `depuis`        date             not null,
      `personne_fk`   integer unsigned not null,
      CONSTRAINT `FK_01` FOREIGN KEY (`personne_fk`) REFERENCES `personne` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `poids` (`mesure`,`depuis`,`personne_fk`) values
      (80, '2022-03-09', 1),
      (85, '2022-12-06', 1)
    --------------
     
    --------------
    select * from `poids`
    --------------
     
    +----+--------+------------+-------------+
    | id | mesure | depuis     | personne_fk |
    +----+--------+------------+-------------+
    |  1 |     80 | 2022-03-09 |           1 |
    |  2 |     85 | 2022-12-06 |           1 |
    +----+--------+------------+-------------+
    --------------
    DROP TABLE IF EXISTS `taille`
    --------------
     
    --------------
    CREATE TABLE `taille`
    ( `id`           integer unsigned not null auto_increment primary key,
      `mesure`       decimal(5,2)     not null,
      `depuis`       date             not null,
      `personne_fk`  integer unsigned not null,
      CONSTRAINT `FK_02` FOREIGN KEY (`personne_fk`) REFERENCES `personne` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `taille` (`mesure`,`depuis`,`personne_fk`) values
      (1.70, '2022-09-15', 1),
      (1.75, '2022-11-28', 1),
      (1.76, '2022-12-06', 1)
    --------------
     
    --------------
    select * from `taille`
    --------------
     
    +----+--------+------------+-------------+
    | id | mesure | depuis     | personne_fk |
    +----+--------+------------+-------------+
    |  1 |   1.70 | 2022-09-15 |           1 |
    |  2 |   1.75 | 2022-11-28 |           1 |
    |  3 |   1.76 | 2022-12-06 |           1 |
    +----+--------+------------+-------------+
    --------------
    drop view if exists `vue_1`
    --------------
     
    --------------
    create view `vue_1` as
      select personne_fk,
             depuis,
             mesure as poids,
             NULL   as taille
        from poids
     
       union
     
      select personne_fk,
             depuis,
             NULL   as poids,
             mesure as taille
        from taille
     
    order by personne_fk, depuis
    --------------
     
    --------------
    select * from `vue_1`
    --------------
     
    +-------------+------------+-------+--------+
    | personne_fk | depuis     | poids | taille |
    +-------------+------------+-------+--------+
    |           1 | 2022-03-09 |    80 |   NULL |
    |           1 | 2022-09-15 |  NULL |   1.70 |
    |           1 | 2022-11-28 |  NULL |   1.75 |
    |           1 | 2022-12-06 |    85 |   NULL |
    |           1 | 2022-12-06 |  NULL |   1.76 |
    +-------------+------------+-------+--------+
    --------------
    drop view if exists `vue_2`
    --------------
     
    --------------
    create view `vue_2` as
      select   personne_fk,
               depuis,
               ( select min(poids)  from `vue_1` where personne_fk = t1.personne_fk and depuis >= t1.depuis) as poids,
               ( select min(taille) from `vue_1` where personne_fk = t1.personne_fk and depuis >= t1.depuis) as taille
     
          from `vue_1` as t1
     
      group by personne_fk, depuis
      order by personne_fk, depuis
    --------------
     
    --------------
    select * from `vue_2`
    --------------
     
    +-------------+------------+-------+--------+
    | personne_fk | depuis     | poids | taille |
    +-------------+------------+-------+--------+
    |           1 | 2022-03-09 |    80 |   1.70 |
    |           1 | 2022-09-15 |    85 |   1.70 |
    |           1 | 2022-11-28 |    85 |   1.75 |
    |           1 | 2022-12-06 |    85 |   1.76 |
    +-------------+------------+-------+--------+
    --------------
    select *, cast(round(poids / (taille * taille), 1) as decimal(5,1)) as IMC
      from `vue_2`
    --------------
     
    +-------------+------------+-------+--------+------+
    | personne_fk | depuis     | poids | taille | IMC  |
    +-------------+------------+-------+--------+------+
    |           1 | 2022-03-09 |    80 |   1.70 | 27.7 |
    |           1 | 2022-09-15 |    85 |   1.70 | 29.4 |
    |           1 | 2022-11-28 |    85 |   1.75 | 27.8 |
    |           1 | 2022-12-06 |    85 |   1.76 | 27.4 |
    +-------------+------------+-------+--------+------+
    --------------
    with vue_1 as (       select personne_fk, depuis, mesure as poids, NULL   as taille from poids
                    union select personne_fk, depuis, NULL   as poids, mesure as taille from taille
                        order by personne_fk, depuis
                  ),
         vue_2 as (       select personne_fk, depuis,
                                 ( select min(poids)  from `vue_1` where personne_fk = t1.personne_fk and depuis >= t1.depuis) as poids,
                                 ( select min(taille) from `vue_1` where personne_fk = t1.personne_fk and depuis >= t1.depuis) as taille
                            from `vue_1` as t1
     
                        group by personne_fk, depuis
                        order by personne_fk, depuis
                  )
                          select *, cast(round(poids / (taille * taille), 1) as decimal(5,1)) as IMC
                            from `vue_2`
    --------------
     
    +-------------+------------+-------+--------+------+
    | personne_fk | depuis     | poids | taille | IMC  |
    +-------------+------------+-------+--------+------+
    |           1 | 2022-03-09 |    80 |   1.70 | 27.7 |
    |           1 | 2022-09-15 |    85 |   1.70 | 29.4 |
    |           1 | 2022-11-28 |    85 |   1.75 | 27.8 |
    |           1 | 2022-12-06 |    85 |   1.76 | 27.4 |
    +-------------+------------+-------+--------+------+
    --------------
    COMMIT
    --------------
     
    Appuyez sur une touche pour continuer...
    Comme on peut le constater, la requête est beaucoup plus compliquée car elle nécessite de remonter les mesures sur les mêmes lignes selectionnées par la colonne "depuis".

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  13. #13
    Futur Membre du Club
    Femme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2023
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2023
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Bonjour Escartefigue,

    Citation Envoyé par escartefigue Voir le message
    Ce modèle de données n'est donc pas optimal
    Oui je m'en rends bien compte. En tout cas merci beaucoup pour vos conseils !

    J'ai quelques questions par rapport à votre modèle:

    -> Dans votre exemple, vous n'utilisez pas la table YM_type_mesure, du coup est-elle vraiment utile ?

    -> Comment faites vous pour voir l'évolution de l'imc ?
    Est ce que vous rajoutez un nouveau type de mesure dans la table YM_type_mesure ?
    Mais cela serait une redondance d'informations vu que l'on peut l'avoir en le calculant par la taille et le poids
    Ou bien faites vous une jointure sur la taille et le poids par rapport à la date de visite ?
    Dans ce cas, pouvez vous m'expliquer comment vous faites s'il vous plait ? Je suis toujours autant perdu avec les jointures avec des dates

  14. #14
    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 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    La table YM_type_mesure est une table de typologie, son but est d'identifier les types de mesure (poids, taille, fréquence cardiaque, tension, albumine, sucre...), de leur associer une unité de mesure, un libellé etc.
    L'intérêt est de fiabiliser les mesures (on évite les graphies différentes du style "mesure de poids", "mesure poids", "mesure masse"... en fonction du rédacteur.
    On peut aussi utiliser une contrainte check ou enum, mais c'est moins riche fonctionnellement.

    Concernant l'IMC, vu qu'il s'agit d'un calcul qui dépend uniquement de la taille et de la masse, il ne faut pas le stocker, ce serait une redondance, on le calculera à chaque fois qu'on en a besoin. Si son utilisation est fréquente, on peut utiliser une colonne calculée d'une vue.
    J'ai donné l'exemple de requête permettant de récupérer la taille et la masse dans ma réponse précédente, il suffit d'ajouter le calcul de l'IMC.
    On veillera seulement à vérifier que les opérandes sont non "null" pour que la division soit possible (diviser par "null" n'ayant pas de sens) : en effet on n'a aucune garantie que la masse et la taille aient été mesurées.

  15. #15
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    Les deux méthodes précédentes répondent à ta question initiale.
    Dans ce qui suit, je ne remets pas la totalité du script sql qui ne change pas.

    Voici celle préconisée par Escartfigue. Elle ne diffère pas trop des deux méthodes précédentes.
    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
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    --------------
    DROP TABLE IF EXISTS `type`
    --------------
     
    --------------
    CREATE TABLE `type`
    ( `id`   integer unsigned not null auto_increment primary key,
      `lib`  varchar(255)     not null
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `type` (`lib`) values
      ('poids'),('taille')
    --------------
     
    --------------
    select * from `type`
    --------------
     
    +----+--------+
    | id | lib    |
    +----+--------+
    |  1 | poids  |
    |  2 | taille |
    +----+--------+
    --------------
    DROP TABLE IF EXISTS `mesure`
    --------------
     
    --------------
    CREATE TABLE `mesure`
    ( `id`            integer unsigned not null auto_increment primary key,
      `mesure`        decimal(5,2)     not null,
      `depuis`        date             not null,
      `personne_fk`   integer unsigned not null,
      `type_fk`       integer unsigned not null,
      CONSTRAINT `FK_03` FOREIGN KEY (`personne_fk`) REFERENCES `personne` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
      CONSTRAINT `FK_04` FOREIGN KEY (`type_fk`)     REFERENCES `type`     (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `mesure` (`mesure`,`depuis`,`personne_fk`,`type_fk`) values
      (80,   '2022-03-09', 1, 1),
      (85,   '2022-12-06', 1, 1),
      (1.70, '2022-09-15', 1, 2),
      (1.75, '2022-11-28', 1, 2),
      (1.76, '2022-12-06', 1, 2)
    --------------
     
    --------------
    select * from `mesure`
    --------------
     
    +----+--------+------------+-------------+---------+
    | id | mesure | depuis     | personne_fk | type_fk |
    +----+--------+------------+-------------+---------+
    |  1 |  80.00 | 2022-03-09 |           1 |       1 |
    |  2 |  85.00 | 2022-12-06 |           1 |       1 |
    |  3 |   1.70 | 2022-09-15 |           1 |       2 |
    |  4 |   1.75 | 2022-11-28 |           1 |       2 |
    |  5 |   1.76 | 2022-12-06 |           1 |       2 |
    +----+--------+------------+-------------+---------+
    --------------
    drop view if exists `vue_3`
    --------------
     
    --------------
    create view `vue_3` as
          select t1.`personne_fk`,
                 t1.`depuis`,
                 t2.lib,
                 case when t1.`type_fk` = 1 then t1.`mesure` else NULL end as poids,
                 case when t1.`type_fk` = 2 then t1.`mesure` else NULL end as taille
            from `mesure`   as t1
      inner join `type`     as t2
              on t2.`id`    = t1.`type_fk`
        order by t1.`personne_fk`, t1.`depuis`
    --------------
     
    --------------
    select * from `vue_3`
    --------------
     
    +-------------+------------+--------+-------+--------+
    | personne_fk | depuis     | lib    | poids | taille |
    +-------------+------------+--------+-------+--------+
    |           1 | 2022-03-09 | poids  | 80.00 |   NULL |
    |           1 | 2022-09-15 | taille |  NULL |   1.70 |
    |           1 | 2022-11-28 | taille |  NULL |   1.75 |
    |           1 | 2022-12-06 | poids  | 85.00 |   NULL |
    |           1 | 2022-12-06 | taille |  NULL |   1.76 |
    +-------------+------------+--------+-------+--------+
    --------------
    drop view if exists `vue_4`
    --------------
     
    --------------
    create view `vue_4` as
      select   personne_fk,
               depuis,
               ( select min(poids)  from `vue_3` where personne_fk = t1.personne_fk and depuis >= t1.depuis) as poids,
               ( select min(taille) from `vue_3` where personne_fk = t1.personne_fk and depuis >= t1.depuis) as taille
     
          from `vue_3` as t1
     
      group by t1.`personne_fk`, t1.`depuis`
      order by t1.`personne_fk`, t1.`depuis`
    --------------
     
    --------------
    select * from `vue_4`
    --------------
     
    +-------------+------------+-------+--------+
    | personne_fk | depuis     | poids | taille |
    +-------------+------------+-------+--------+
    |           1 | 2022-03-09 | 80.00 |   1.70 |
    |           1 | 2022-09-15 | 85.00 |   1.70 |
    |           1 | 2022-11-28 | 85.00 |   1.75 |
    |           1 | 2022-12-06 | 85.00 |   1.76 |
    +-------------+------------+-------+--------+
    --------------
    select *, cast(round(poids / (taille * taille), 1) as decimal(5,1)) as IMC
      from `vue_4`
    --------------
     
    +-------------+------------+-------+--------+------+
    | personne_fk | depuis     | poids | taille | IMC  |
    +-------------+------------+-------+--------+------+
    |           1 | 2022-03-09 | 80.00 |   1.70 | 27.7 |
    |           1 | 2022-09-15 | 85.00 |   1.70 | 29.4 |
    |           1 | 2022-11-28 | 85.00 |   1.75 | 27.8 |
    |           1 | 2022-12-06 | 85.00 |   1.76 | 27.4 |
    +-------------+------------+-------+--------+------+
    --------------
    COMMIT
    --------------
     
    Appuyez sur une touche pour continuer...
    Avec toutes ces solutions, je pense que tu es plus à même de résoudre ton problème.
    Tu peux mettre ton sujet à résolu !

    Cordialement.
    Artemus24.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  16. #16
    Futur Membre du Club
    Femme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2023
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Maritime (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2023
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Oui, merci à tout le monde pour votre aide !

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

Discussions similaires

  1. Jointure complexe / intervalle de date
    Par Isildur dans le forum Langage SQL
    Réponses: 14
    Dernier message: 17/12/2011, 03h30
  2. [debutant] Intervalles de dates
    Par dormouse dans le forum Collection et Stream
    Réponses: 10
    Dernier message: 29/03/2006, 19h48
  3. calculer un intervalle de dates
    Par vodevil dans le forum Modules
    Réponses: 3
    Dernier message: 16/01/2006, 20h04
  4. Intervalle de Dates
    Par Philofish dans le forum Langage SQL
    Réponses: 6
    Dernier message: 06/09/2005, 11h02
  5. selection intervalle de dates
    Par jax69 dans le forum Access
    Réponses: 2
    Dernier message: 22/06/2005, 13h58

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