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

  1. #1
    Membre habitué
    Comment avoir la liste des patients absents à leurs 3 derniers Rdv
    Bonjour,
    J'ai 1 table Patient (Id, Nom...) et 1 Table RdvPatient (IdPatient, Date, IsAbsent...).
    Comment demander la liste des patient absents à leurs X derniers Rdv (par date), X devant être 1 paramètre passé.
    Merci pour votre aide
    PS : Sql Server 2014

  2. #2
    Rédacteur

    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
    WITH 
    T0 AS
    -- recherche des trois derniers RV du patient
    (SELECT PRV_ID, PAT_ID,  
            ROW_NUMBER() OVER(PARTITION BY PAT_ID ORDER BY RDV_DATE_HEURE DESC) AS N
     FROM   T_PATIENT_RENDEZVOUS_PRV),
    T1 AS
    -- y a t-il un des 3 derniers RV qui a été honoré ?
    (SELECT PAT_ID
     FROM   T_PATIENT_RENDEZVOUS_PRV AS PRV
            JOIN T0 ON PRV.PRV_ID = T0.PRV
     WHERE  PRV_PRESENT = 10)
    -- résultat final
    SELECT *
    FROM   T_PATIENT_PAT AS PAT
    WHERE  PAT_ID IN (SELECT PAT_ID
                      FROM   T0
                      EXCEPT
                      SELECT PAT_ID
                      FROM   T1);


    Pour vous former, mon livre sur SQL :


    A +
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  3. #3
    Membre confirmé
    Bonjour,

    Voici une solution utilisant des fonctions analytiques. J'ai supposé que IsAbsent = 1 pour signaler une absence. La requête ne montre que les patients ayant manqué leurs X derniers rdv, avec les dates correspondantes:

    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
    with rdv as (select p.id,
                        p.nom, 
                        r.date_rdv,
                        row_number() over (partition by p.id order by r.date_rdv desc) rn,
                        sum(case when r.isabsent = 1 then 1 else 0 end) over (partition by p.id order by r.date_rdv desc) somme_rdv_absent
                 from patient p
                 join RdvPatient r on r.idpatient = p.id
                ),
         X_derniers_rdv as (select id, 
                                   nom,
                                   date_rdv,
                                   max(somme_rdv_absent) over (partition by id) nb_rdv_manques
                            from rdv
                            where rn <= :X
                           )
    select id, 
           nom,
           date_rdv
    from X_derniers_rdv
    where nb_rdv_manques = :X;

  4. #4
    Membre confirmé
    Si tu es en Oracle 12c, c'est encore plus simple avec une requête match_recognize:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    select id, nom, date_rdv 
    patient p
    join RdvPatient r on r.idpatient = p.id
    match_recognize
     (partition by id
      order by date_rdv desc
      all rows per match
      pattern(^rdv_manque{:X})
      define rdv_manque as rdv_manque.isabsent=1
     );

  5. #5
    Modérateur

    bonjour,

    Ou bien :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    WITH RangRDV AS (
    		SELECT *, ROW_NUMBER() OVER(PARTITION BY idpatient ORDER BY dte DESC) AS RN
    		FROM RdvPatient
    	)
    SELECT p.Nom
    FROM Patient AS P
    INNER JOIN RangRDV AS R
    	ON	R.idpatient = P.id
    WHERE RN <= @x
    GROUP BY p.Nom
    HAVING SUM(IsAbsent)  = 3

  6. #6
    Membre habitué
    Citation Envoyé par vanagreg Voir le message
    Bonjour,

    Voici une solution utilisant des fonctions analytiques. J'ai supposé que IsAbsent = 1 pour signaler une absence. La requête ne montre que les patients ayant manqué leurs X derniers rdv, avec les dates correspondantes:

    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
    with rdv as (select p.id,
                        p.nom, 
                        r.date_rdv,
                        row_number() over (partition by p.id order by r.date_rdv desc) rn,
                        sum(case when r.isabsent = 1 then 1 else 0 end) over (partition by p.id order by r.date_rdv desc) somme_rdv_absent
                 from patient p
                 join RdvPatient r on r.idpatient = p.id
                ),
         X_derniers_rdv as (select id, 
                                   nom,
                                   date_rdv,
                                   max(somme_rdv_absent) over (partition by id) nb_rdv_manques
                            from rdv
                            where rn <= :X
                           )
    select id, 
           nom,
           date_rdv
    from X_derniers_rdv
    where nb_rdv_manques = :X;
    Merci pour ton aide.
    Le résultat n'est pas tout à fait celui attendu : si je demande la liste des ceux absents aux 3 derniers Rdv, le patient sort 3 fois avec chaque fois la date du Rdv.
    ...je voulais 1 liste de patients (chacun 1 seule fois), pas 1 liste de Rdv manqués.
    Je pense qu'on doit pouvoir la modifier pour cela mais c'est trop complexe pour mon petit niveau...

  7. #7
    Membre habitué
    Citation Envoyé par SQLpro Voir le message
    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
    WITH 
    T0 AS
    -- recherche des trois derniers RV du patient
    (SELECT PRV_ID, PAT_ID,  
            ROW_NUMBER() OVER(PARTITION BY PAT_ID ORDER BY RDV_DATE_HEURE DESC) AS N
     FROM   T_PATIENT_RENDEZVOUS_PRV),
    T1 AS
    -- y a t-il un des 3 derniers RV qui a été honoré ?
    (SELECT PAT_ID
     FROM   T_PATIENT_RENDEZVOUS_PRV AS PRV
            JOIN T0 ON PRV.PRV_ID = T0.PRV
     WHERE  PRV_PRESENT = 10)
    -- résultat final
    SELECT *
    FROM   T_PATIENT_PAT AS PAT
    WHERE  PAT_ID IN (SELECT PAT_ID
                      FROM   T0
                      EXCEPT
                      SELECT PAT_ID
                      FROM   T1);

    Merci, ça a l'air de faire pas mal mais je ne comprends pas ou je peux donner le nombre d'absences souhaitées...

  8. #8
    Membre habitué
    Citation Envoyé par vanagreg Voir le message
    Si tu es en Oracle 12c, c'est encore plus simple avec une requête match_recognize:
    ...hélas non, j'avais oublié de préciser : Sql Server 2014

  9. #9
    Membre habitué
    Citation Envoyé par aieeeuuuuu Voir le message
    bonjour,

    Ou bien :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    WITH RangRDV AS (
    		SELECT *, ROW_NUMBER() OVER(PARTITION BY idpatient ORDER BY dte DESC) AS RN
    		FROM RdvPatient
    	)
    SELECT p.Nom
    FROM Patient AS P
    INNER JOIN RangRDV AS R
    	ON	R.idpatient = P.id
    WHERE RN <= @x
    GROUP BY p.Nom
    HAVING SUM(IsAbsent)  = 3
    Merci, ça me plait bien comme technique mais j'avais simplifié en pensant que je pourrais adapter... et je n'y arrive pas.
    En fait je n'ai pas IsAbs = 1 mais AbsID qui vaut 1 à 49 qd c'est 1 absence...
    Si tu pouvais me proposer ta solution en adaptant cette variante ce serait parfait.

  10. #10
    Modérateur

    et quand ce n'est pas une absence ?

  11. #11
    Membre confirmé
    Citation Envoyé par bib34690 Voir le message
    Merci pour ton aide.
    Le résultat n'est pas tout à fait celui attendu : si je demande la liste des ceux absents aux 3 derniers Rdv, le patient sort 3 fois avec chaque fois la date du Rdv.
    ...je voulais 1 liste de patients (chacun 1 seule fois), pas 1 liste de Rdv manqués
    Oui c'était pour avoir les dates de rdv manqués. Si tu n'en as pas besoin alors utilises la version de aieeeuuuuu.

  12. #12
    Membre confirmé
    tu peux modifier la clause having:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    HAVING SUM(case when IsAbsent between 1 and 49 then 1 else 0 end)  = 3

  13. #13
    Modérateur

    Sur SQL-Server vous pouvez faire comme ceci :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    declare @N int;
    set @N=3;
     
         select P.Id, P.Nom
           from Patient as P
    cross apply (  select top (@N)
                           case when R.AbsID between 1 and 49 then 1 else 0 end
                     from RdvPatient as R
                    where R.IdPatient = P.Id
                 order by R.[Date] desc
                ) as A (IsAbsent)
       group by P.Id, P.Nom
         having sum(A.IsAbsent) = @N;

    Le 3 étant dans le top du cross apply et dans le having final.

    Edit: prise en compte de l'AbsID et paramétrisation du nombre d'absences.

  14. #14
    Membre habitué
    Citation Envoyé par aieeeuuuuu Voir le message
    et quand ce n'est pas une absence ?
    0= Present
    51 à 100 c'est le médecin qui est absent.
    On fait un suivi des absences du patient : les abs. du médecin sont considérées comme des présences pour cette requête

  15. #15
    Membre habitué
    Citation Envoyé par vanagreg Voir le message
    tu peux modifier la clause having:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    HAVING SUM(case when IsAbsent between 1 and 49 then 1 else 0 end)  = 3
    PARFAIT : fait le job, simple à comprendre, rapide.
    Merci

  16. #16
    Membre habitué
    Je n'ai pas réussi à comprendre et à faire fonctionner la solution de SQLpro. Dommage, j'aurais bien aimé comparer.
    La solution de vanareg ne répond pas à mon besoin.
    La solution de Waldar etait la plus concise et me plaisait bien mais elle etait trés lente.
    J'ai retenu la solution de aieeeuuuuu : 3 fois plus rapide sur ma base, simple et concise.

    Merci à SQLpro, vanagreg, Waldar et aieeeuuuuu.
    Mon problème a été réglé rapidement et efficacement grâce à vous.
    Bon WE

  17. #17
    Modérateur

    bonjour,

    LA solution de Waldar pourrait être efficace, mais à condition qu'il y ait un index adéquat :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
     
    CREATE INDEX IX_RdvPatient_IdPatient ON RdvPatient (IdPAtient) INCLUDE (IsAbsent)

  18. #18
    Rédacteur

    Il manquait dans ma solution un petit bout de 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
    20
    21
    WITH 
    T0 AS
    -- recherche des trois derniers RV du patient
    (SELECT PRV_ID, PAT_ID,  
            ROW_NUMBER() OVER(PARTITION BY PAT_ID ORDER BY RDV_DATE_HEURE DESC) AS N
     FROM   T_PATIENT_RENDEZVOUS_PRV),
    T1 AS
    -- y a t-il un des 3 derniers RV qui a été honoré ?
    (SELECT PAT_ID
     FROM   T_PATIENT_RENDEZVOUS_PRV AS PRV
            JOIN T0 ON PRV.PRV_ID = T0.PRV
     WHERE  PRV_PRESENT = 1
       AND  N <= 3) --> nombre de RV consécutifs
    -- résultat final
    SELECT *
    FROM   T_PATIENT_PAT AS PAT
    WHERE  PAT_ID IN (SELECT PAT_ID
                      FROM   T0
                      EXCEPT
                      SELECT PAT_ID
                      FROM   T1);


    A +
    Cette signature n'a pas pu être affichée car elle comporte des erreurs.

  19. #19
    Membre habitué
    Merci pour ces précisions.
    J'ai pu faire les tests avec toutes ces solutions, celle de aieeeuuuuu reste la plus rapide et la plus simple.
    ...fin des tests, dossier clos !