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

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

Langage SQL Discussion :

3 tables -> 2 sous-tables -> 1 table résultat


Sujet :

Langage SQL

  1. #1
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 64
    Points : 36
    Points
    36
    Par défaut 3 tables -> 2 sous-tables -> 1 table résultat
    Bonjour,
    J'ai une base de donnée Sybase. Parmi un grand nombre de tables, je suis intéressé par 3 d'entre elles:
    1-Patient (contenant les données démographiques de patients)
    2-TargetVol (Diagnostic, cible du traitement, stade, etc...)
    3-Series (Séries de traitements, cible du traitement, etc...)
    La valeur commune entre toutes les tables est l'ID d'un patient.

    Je dois compulser des données provenant de ces trois tables: quel est le stade de la maladie (table TargetVol) pour les patients (table Patient) qui ont fini le traitement (table Series et Patient).

    J'ai essayé de saucissonner le problème:
    1-Quels sont les séries de traitements terminées pour les patients qui ont fini le traitement (il peut exister des séries terminées pour des patients qui n'ont pas fini le traitement - TreatStat différent de SEP - et des séries terminées pour des patients qui ont fini le traitement et déjà archivées - TreatStat = SEP mais SeriStat différent de 5):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT DISTINCT p.PIDno, p.PersNo, t.TargetNo
    FROM Patient p
    	INNER JOIN Series t
    	ON p.PIDno=t.PIDno
    WHERE p.TreatStat LIKE 'SEP' AND t.SeriStat = 5
    donnant comme résultat:

    PIDno PersNo TargetNo
    4706 28.11.07bl 4
    1138 36.06.18dr 3
    1138 36.06.18dr 2
    3948 39.02.20za 3
    4707 52.02.23pg 1
    4716 57.05.23ms 4
    4716 57.05.23ms 3
    4716 57.05.23ms 2
    4716 57.05.23ms 1
    4695 59.09.26mmmd 1

    C'est un premier pas. J'ai tous les patients cherchés, il ne manque que le stade.

    2- Quel est le stade de la maladie pour les patients qui ont fini le traitement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT DISTINCT q.PIDno, q.PersNo, c.TargetNo, c.Stage
    FROM Patient q
    	INNER JOIN TargetVol c
    	ON q.PIDno=c.PIDno
    WHERE q.TreatStat LIKE 'SEP'
    avec pour résultat

    PIDno PersNo TargetNo Stade
    4706 28.11.07bl 1 ---
    4706 28.11.07bl 4 ---
    4706 28.11.07bl 2 ---
    4706 28.11.07bl 3 ---
    1138 36.06.18dr 3 ---
    1138 36.06.18dr 2 ---
    1138 36.06.18dr 1 T3N0M0
    3948 39.02.20za 2 ---
    3948 39.02.20za 3 ---
    3948 39.02.20za 1 ---
    4707 52.02.23pg 1 pT3bpN0M0
    4716 57.05.23ms 4 T2 N2c Mx
    4716 57.05.23ms 3 T2 N2c Mx
    4716 57.05.23ms 1 T2 N2c Mx
    4716 57.05.23ms 2 T2 N2c Mx
    4695 59.09.26mmmd 1 pT1cpN0M0

    La différence entre ces deux résultats est que certaines lignes apparaissent en plus dans le deuxième résultat. Par conséquent, à mon sens, la solution à mon problème est une jointure de ces deux résultats de telle sorte que toutes les lignes du premier soient complétées par les information supplémentaires apparaissant dans le second, seulement pour les lignes qui apparaissent dans les deux. J'ai essayé (entre autres) le code:

    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
    SELECT DISTINCT a.PIDno, a.PersNo, a.Stage, a.TargetNo
    FROM
    (
    SELECT DISTINCT q.PIDno, q.PersNo, c.TargetNo, c.Stage
    	FROM Patient q
    		INNER JOIN TargetVol c
    		ON q.PIDno=c.PIDno
    	WHERE q.TreatStat LIKE 'SEP'
    ) a
    ,
    (
    	SELECT DISTINCT p.PIDno, p.PersNo, t.TargetNo
    	FROM Patient p
    		INNER JOIN Series t
    		ON p.PIDno=t.PIDno
    	WHERE p.TreatStat LIKE 'SEP' AND t.SeriStat = 5
    ) b
    HAVING a.TargetNo = b.TargetNo
    ORDER BY 2 ASC
    mais le résultat est sensiblement égal au deuxième... c'est comme si mon code ne tenait pas compte que tous les t.TargetNo n'apparaissent pas dans la table a!

    J'ai l'impression que c'est un problème trivial, mais je ne m'en sors pas. Je vous remercie de votre aide.

  2. #2
    Membre éprouvé Avatar de Mathusalem
    Profil pro
    IT moa
    Inscrit en
    Décembre 2003
    Messages
    1 008
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : IT moa

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 008
    Points : 1 067
    Points
    1 067
    Par défaut
    je ne capte pas tout, mais le having me choque, remplace le par un where ça ira mieux

  3. #3
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 64
    Points : 36
    Points
    36
    Par défaut
    Avec WHERE, ça donne le même résultat.

  4. #4
    Expert éminent
    Homme Profil pro
    Big Data / Freelance EURL
    Inscrit en
    Mars 2003
    Messages
    2 124
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Big Data / Freelance EURL

    Informations forums :
    Inscription : Mars 2003
    Messages : 2 124
    Points : 7 291
    Points
    7 291
    Par défaut
    mon dieu. C'est un exemple typique de la mauvaise utilisation de DISTINCT qui ne devrait être utilisé que parcimonieusement. D'ailleurs je préfères en général GROUP BY.

    En plus tu nous présentes certes une description métier des tables mais aucune description technique (CREATE TABLE). Ce qui fait qu'on ne peut pas comprendre la modélisation pour les niveaux de regroupement (et pour remettre en cause éventuellement cette modélisation). Et visiblement c'est nécessaire de comprendre les niveaux de regroupement vu le nombre de DISTINCT qu'on voit.

    Attention la plupart des SGBDR font sauter l'index avec le LIKE. Le LIKE n'a aucun intérêt s'il n'y a pas un des 2 jokers "_" ou" %".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT p.PIDno, p.PersNo, COALESCE( t.Stage,c.TargetNo), c.Stage
    FROM Patient p
    INNER JOIN TargetVol c
    		ON p.PIDno=c.PIDno
    LEFT JOIN Series t
    		ON p.PIDno=t.PIDno AND t.SeriStat = 5
    WHERE p.TreatStat= 'SEP'
    GROUP BY p.PIDno, p.PersNo, COALESCE( t.Stage,c.TargetNo), c.Stage
    ou


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT p.PIDno, p.PersNo, s_t.TargetNo, s_t.Stage
    FROM Patient p
    LEFT JOIN (
    		SELECT c.PIDno,c.TargetNo,c.stage
    		FROM TargetVol c
    		UNION -- UNION agrège, UNION ALL n'agrège pas 
    		SELECT t.PIDno,t.TargetNo,null
    		FROM TargetVol t
    		WHERE t.SeriStat = 5
    		) s_t
    	ON p.PIDno=s_t.PIDno
    WHERE p.TreatStat = 'SEP'
    et rajouter éventuellement un DISTINCT si vraiment ça ne suffit pas.

  5. #5
    Nouveau membre du Club
    Inscrit en
    Août 2007
    Messages
    64
    Détails du profil
    Informations forums :
    Inscription : Août 2007
    Messages : 64
    Points : 36
    Points
    36
    Par défaut
    Merci beaucoup pour ta réponse qui m'a fait progresser vers la solution.
    1-Je n'ai pas réussi à faire tourner ton premier code: il donnait une erreur du type "impossible à comparer des CHAR avec des INT". Je n'ai pas investigué plus loin.
    2-Le deuxième code m'a fait comprendre qu'il fallait légèrement le modifier en remplaçant l'UNION par une intersection. D'où

    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
    SELECT p.PIDno, p.PersNo, s_t.TargetNo, s_t.Diag, s_t.Stage
    FROM Patient p
    LEFT JOIN 
    		(
    		SELECT DISTINCT a.PIDno, a.TargetNo, a.SeriStat, c.Stage, c.Diag
    		FROM Series a
    		LEFT JOIN
    			(
    			SELECT b.PIDno, b.TargetNo, b.Stage, b.Diag
    			FROM TargetVol b
    			) c
    		ON a.TargetNo = c.TargetNo AND a.PIDno=c.PIDno
    		WHERE a.SeriStat = 5
    		) s_t
    		ON p.PIDno=s_t.PIDno
    WHERE p.TreatStat = 'SEP'
    ORDER BY 2 ASC
    donne le résultat cherché. J'ai dû mettre un DISTINCT pour des raisons internes à la constitution de la table (à mon avis).

    Si une programmation plus élégante existe, je suis intéressé.

    Encore merci.

    PS- Je ne suis qu'un utilisateur final et programmateur de requêtes SQL depuis 2 jours... Je ne peux donc donner aucune indication sur la façon dont les tables sont créées et reste sans doute dans la trivialité pour mes questions...

    PS2- Il est où le bouton résulu?

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

Discussions similaires

  1. impression sous builder (d'une table mysql)
    Par Link45 dans le forum C++Builder
    Réponses: 15
    Dernier message: 13/03/2006, 21h31
  2. Réponses: 3
    Dernier message: 27/10/2004, 23h15
  3. mise à jour d'une table d'interbase sous delphi
    Par kouraichi35 dans le forum Bases de données
    Réponses: 2
    Dernier message: 19/10/2004, 13h09
  4. 'SHOW TABLES' marche pas sous postgresql !?
    Par fet dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 13/05/2004, 09h28

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