2015-10-20 4 views
2

J'ai une base de données de rapports de radiologie que j'ai extraits pour des incidents de nodules pulmonaires. Chaque patient a un numéro d'enregistrement médical et chaque procédure a un numéro d'accès unique. Par conséquent, un MRN peut avoir plusieurs numéros d'accès pour les procédures de différence. Les numéros d'accès sont ascendants, donc si un patient a plusieurs numéros d'accession, le plus grand numéro d'accession est la dernière procédure. Je dois:Sous-requête corrélée dans SQL

  • Identifier la plus ancienne (initiale) Etude
  • Trouvez la prochaine étude qui vient plus tôt après la inital
  • Calculer la différence de temps entre chaque intervalle

Je crois que ce problème peut être résolu en utilisant une sous-requête corrélée. Cependant, je ne suis pas encore assez expert en SQL pour résoudre ce problème. J'ai essayé de me joindre à la table et de trouver l'adhésion maximale pour chaque sous-requête. Voici un exemple de code pour créer un jeu de données:

CREATE TABLE Stack_Example (Rank, Accession1, MRN1, Textbox2, Textbox47,Textbox43,Textbox45,ReadBy,SignedBy,Addendum1,ReadDate,SignedDate,Textbox49,Result,Impression,max_size_nodule, max_nodule_loc, max_nodule_type) 


    INSERT INTO Stack_Example 
VALUES ("10", "33399", "001734", "5/21/1965", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "COMB, YAHAIR", "YES", "12/19/2014 11:48", "12/19/2014 17:50", "TEXT", "Results of Nodules!","Impressions of Nodules","3.0", "right middle lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("9", "33104", "001734", "5/21/1965", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "12/21/2013 06:52", "01/21/2014 06:52", "TEXT", "Results of Nodules!","Impressions of Nodules","3.7", "right upper lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("9", "33374", "001734", "5/21/1965", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "01/21/2014 08:19", "01/21/2014 06:52", "TEXT", "Results of Nodules!","Impressions of Nodules","2.1", "right lower lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("1", "34453", "001734", "5/21/1965", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "03/14/2014 09:14", "03/14/2014 09:14", "TEXT", "Results of Nodules!","Impressions of Nodules","1.4", "left upper lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("1", "27122", "80592", "1/14/1984", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "06/26/2013 10:20", "06/26/2013 10:20", "TEXT", "Results of Nodules!","Impressions of Nodules","2.5", "left upper lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("1", "27248", "80592", "1/14/1984", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "08/01/2013 06:23", "08/01/2013 06:23", "TEXT", "Results of Nodules!","Impressions of Nodules","4.0", "left lower lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("1", "28153", "35681", "03/01/1990", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "09/14/2012 05:00", "09/14/2012 05:00", "TEXT", "Results of Nodules!","Impressions of Nodules","4.0", "left lower lobe","None Found") 

INSERT INTO Stack_Example 
VALUES ("1", "29007", "35681", "03/01/1990", "CTS", "3341", "ROUTINE", "TUCK, YOURPANTSIN", "PICK, YASELFUP", "YES", "11/16/2012 08:23", "11/16/2012 08:23", "TEXT", "Results of Nodules!","Impressions of Nodules","3.5", "right lower lobe","None Found") 

Il s'agit évidemment de fausses données. Ce que j'ai essayé de faire est de rejoindre la table sur elle-même avec une sous-requête corrélée. Comme si:

SELECT DISTINCT a.Accession1, a.MRN1, a.ReadDate, p.Accession1, p.ReadDate 
FROM Stack_Example as a 
INNER JOIN Stack_Example as p on a.MRN1 = p.MRN1 
WHERE a.Accession1 = 
(SELECT max(Accession1) 
FROM Stack_Example as b 
WHERE a.MRN1 = b.MRN1 AND 
a.Accession1 != p. Accession1) 
ORDER BY a.MRN1 

Idéalement ce que je voudrais une table principale avec un NRM pour chaque patient sur des lignes et des adhésions pour chaque NRM sous forme de colonnes (à côté des dates pour les adhésions, etc.). Quelque chose comme ceci:

| MRN  | Accession (First Follow-up) | Date First Followup |Accession (Second Follow-up)..| Date Second Follow up | etc. 
|:-----------|----------------------------:|:-------------------:| 
| 001734  |  33374     | ......  
| 80592  |  27248     | ......  

Je crois que la sous-requête j'ai besoin d'une série de jointures de gauche; Cependant, y a-t-il une meilleure façon de le faire? Certains patients ont plus de 7 suivis. Appréciez toute aide et désolé pour la longue explication. J'espère que le formatage est correct.

+0

Vous pouvez également inclure un travail www.SqlFiddle.com, qui aident à tester les réponses. –

Répondre

1

Vous êtes sur la bonne voie. vous pouvez le faire avec une auto-jointure et une sous-requête. Le tableau doit être joint à lui-même sur le MRN1, et l'Accession1 du dernier enregistrement est égal à la plus petite Accession1 pour ce MRN1 qui est supérieure au MRN1 du premier enregistrement (le MRN1 suivant). La jointure à gauche permet à la requête de générer un rapport sur tous les enregistrements, même le dernier (qui n'a pas de successeur).

cette requête génère toutes les paires d'études adjacentes:

Select a.ReadDate ARead, b.ReadDate BRead, 
     b.ReadDate-A.ReadDate elapsed, 
     a.*, b.*, 
From table a 
    left Join table b 
     on b.MRN1 = a.MRN1 
      and b.Accession1 = 
       (Select min(Accession1) From table 
       where MRN1 = a.MRN1 
        and Accession1 > a.Accession1) 

cette requête génère les trois premières études:

Select a.ReadDate ARead, b.ReadDate BRead, c.ReadDate CRead, 
     b.ReadDate-A.ReadDate elapsedAB, 
     c.ReadDate-b.ReadDate elapsedBCB 
From table a 
    left Join table b 
     on b.MRN1 = a.MRN1 
      and b.Accession1 = 
       (Select min(Accession1) From table 
       where MRN1 = a.MRN1 
        and Accession1 > a.Accession1) 
    left Join table c 
     on c.MRN1 = a.MRN1 
      and c.Accession1 = 
       (Select min(Accession1) From table 
       where MRN1 = a.MRN1 
        and Accession1 > b.Accession1) 
Where A.ReadDate = 
     (Select Min(readDate) from table 
     where MRN1 = a.MRN1) 
+0

Salut Charles, merci pour la réponse. Votre code fonctionne cependant, je voudrais que les MRN ne se répètent pas à travers les lignes. Au lieu de cela, je cherche à avoir MRNs sur une ligne avec chaque suivi en colonnes. Dans ce code actuel, si une personne a 4 études, elles seront sur 4 lignes différentes. J'essaie d'avoir le MRN sur une ligne avec la première (étude la plus ancienne) dans la première colonne et chaque étude dans des colonnes supplémentaires allant vers la droite. Merci. –

+0

@david, c'est plus difficile, il faut que la requête génère dynamiquement un nombre différent de colonnes dans la sortie pour chaque ligne. –

0

Je ne sais pas si vous voulez que toutes les plages ou tout simplement les deux premiers. Charles requête que je crois fournir tout.

Celui-ci juste les deux premiers.

SELECT * 
FROM  YourTable as O -- oldest 
LEFT JOIN YourTable as neO -- next oldest 
     ON O.MRN1 = neO.MRN1 
WHERE 
     O.Accession1 = (SELECT MIN(Accession1) 
         FROM YourTable A 
         WHERE A.MRN1 = O.MRN1) 

    AND neO.Accession1 = (SELECT MIN(Accession1) 
         FROM YourTable A 
         WHERE A.MRN1 = O.MRN1 
          AND A.Accession1 <> O.Accession1) 
+0

Salut Juan, votre exemple fonctionne pour la première étude de suivi. Cependant, comment puis-je ajouter des jointures à gauche supplémentaires pour plus de suivi? Ce code fait exactement ce dont j'ai besoin pour le premier suivi, une ligne pour MRN avec la plus ancienne en premier puis la suivante ... Je voudrais ajouter chaque suivi allant jusqu'à environ 7. –

+0

Donc vous voulez une fusion entre Charles et le mien ou une amélioration de la requête Charles? Avez-vous vu http://www.sqlfiddle.com/? J'essaye de télécharger votre échantillon mais j'ai obtenu une erreur de syntaxe et je n'ai pas eu le temps de le réparer. –

+0

En effet. Ajouter quelque chose comme: 'ET neO2.Accession1 = (SELECT MIN (adhésion1) DE Four_mm_or_Less A OU A.MRN1 = O.MRN1 ET A.Accession1 <> O.Accession1 \t \t \t \t \t \t ET A. Accession1 <> neO.Accession1) ' Au dernier code de votre script, il sera étendu au suivi suivant, mais exclut tous les cas où il n'y a pas eu 2 suivis. J'essaie de garder ces MRN sans suivi, mais j'ai juste des valeurs nulles pour les champs où il n'y a pas de suivi. –

0

Vous pouvez poster un minimal working example, votre exemple contient plusieurs colonnes qui ne sont pas nécessaires et rendre les choses compliquées.

Le schéma suivant est sur SQL Fiddle, voir ci-dessous. J'ai changé l'année de Accession 34453 en 2015, l'ordre d'accession et les dates étaient erronés.

CREATE TABLE Stack_Example (
    Accession  VARCHAR(32), 
    MRN    VARCHAR(32), 
    ReadDate   DATETIME 
); 

INSERT INTO Stack_Example 
VALUES ("33399", "001734", STR_TO_DATE("12/19/2014 11:48", "%m/%d/%Y %h:%i")), 
     ("33104", "001734", STR_TO_DATE("12/21/2013 06:52", "%m/%d/%Y %h:%i")), 
     ("33374", "001734", STR_TO_DATE("01/21/2014 08:19", "%m/%d/%Y %h:%i")), 
     ("34453", "001734", STR_TO_DATE("03/14/2015 09:14", "%m/%d/%Y %h:%i")), 
     ("27122", "80592", STR_TO_DATE("06/26/2013 10:20", "%m/%d/%Y %h:%i")), 
     ("27248", "80592", STR_TO_DATE("08/01/2013 06:23", "%m/%d/%Y %h:%i")), 
     ("28153", "35681", STR_TO_DATE("09/14/2012 05:00", "%m/%d/%Y %h:%i")), 
     ("29007", "35681", STR_TO_DATE("11/16/2012 08:23", "%m/%d/%Y %h:%i")); 

Groupe Concat toutes les accessions Précédent
Il semble que vous voulez avoir un nombre variable de colonnes, ou créer de façon dynamique ces colonnes. Pour autant que je sache, cela ne fonctionne pas. Comme proposé dans les autres réponses, vous devez ajouter un LEFT JOIN pour chaque colonne. Cependant, dans MySQL, vous pouvez utiliser GROUP_CONCAT pour concaténer les valeurs d'un groupe. Vos valeurs ne seront plus dans des colonnes individuelles, mais le résultat pourrait être proche de ce que vous attendez. Ensuite, pour générer des différences entre deux dates consécutives, vous disposez de fonctions de fenêtrage dans PostgreSQL. En MySQL, vous pouvez utiliser nested sets or adjacent lists.

SELECT S.MRN, 
     GROUP_CONCAT('Acc: ', S.Accession, 
        ' Date: ', S.ReadDate, 
        ' Days to prev.: ', IFNULL(Diff, 0) 
        ORDER BY Accession SEPARATOR ' :: ') 
FROM (
    SELECT S0.MRN, 
     S0.Accession, 
     S0.ReadDate, 
     TIMESTAMPDIFF(DAY, S1.ReadDate, S0.ReadDate) AS Diff 
    FROM stack_example S0 
    -- join on previous accession 
    LEFT JOIN stack_example S1 
    ON S1.MRN = S0.MRN 
    AND S1.Accession = (SELECT MAX(S2.Accession) 
         FROM stack_example S2 
         WHERE S2.MRN = S0.MRN 
          AND S2.Accession < S0.Accession) 
) S 
GROUP BY MRN; 

est peut-être à ce que vous recherchez, Results sur SQL Fiddle.

| MRN | Result                                                        | 
|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 
| 001734 | Acc: 33104 Date: 2013-12-21 06:52:00 Days to prev.: 0 :: Acc: 33374 Date: 2014-01-21 08:19:00 Days to prev.: 31 :: Acc: 33399 Date: 2014-12-19 11:48:00 Days to prev.: 332 :: Acc: 34453 Date: 2015-03-14 09:14:00 Days to prev.: 84 | 
| 35681 | Acc: 28153 Date: 2012-09-14 05:00:00 Days to prev.: 0 :: Acc: 29007 Date: 2012-11-16 08:23:00 Days to prev.: 63                              | 
| 80592 | Acc: 27122 Date: 2013-06-26 10:20:00 Days to prev.: 0 :: Acc: 27248 Date: 2013-08-01 06:23:00 Days to prev.: 35                              | 

fixe Nombre de Adhésion Adhésions Précédent
requête suivante est la même requête Charles Bretana a déjà posté. Il rejoint un nombre fixe d'accessions. L'inconvénient de cette requête est que vous n'obtenez pas les accessions les plus récentes, mais les sept/quatre accessions les plus anciennes.

SELECT S0.MRN, 
     S0.Accession, S0.ReadDate, 
     0, 
     S1.Accession, S1.ReadDate, 
     TIMESTAMPDIFF(DAY, S0.ReadDate, S1.ReadDate), 
     S2.Accession, S2.ReadDate, 
     TIMESTAMPDIFF(DAY, S1.ReadDate, S2.ReadDate), 
     S3.Accession, S3.ReadDate, 
     TIMESTAMPDIFF(DAY, S2.ReadDate, S3.ReadDate) 

FROM stack_example S0 
LEFT JOIN stack_example S1 
    ON S1.MRN = S0.MRN 
AND S1.Accession = (SELECT MIN(SX.Accession) 
         FROM stack_example SX 
         WHERE SX.MRN = S0.MRN 
         AND SX.Accession > S0.Accession) 
LEFT JOIN stack_example S2 
    ON S2.MRN = S0.MRN 
AND S2.Accession = (SELECT MIN(SX.Accession) 
         FROM stack_example SX 
         WHERE SX.MRN = S1.MRN 
         AND SX.Accession > S1.Accession) 
LEFT JOIN stack_example S3 
    ON S3.MRN = S0.MRN 
AND S3.Accession = (SELECT MIN(SX.Accession) 
         FROM stack_example SX 
         WHERE SX.MRN = S2.MRN 
         AND SX.Accession > S2.Accession) 

WHERE S0.Accession = (SELECT MIN(SX.Accession) 
         FROM stack_example SX 
         WHERE SX.MRN = S0.MRN) 
; 

Résultat

| MRN | Accession |     ReadDate | 0 | Accession |     ReadDate | TIMESTAMPDIFF | Accession |     ReadDate | TIMESTAMPDIFF | Accession |    ReadDate | TIMESTAMPDIFF | 
|--------|-----------|-----------------------------|---|-----------|----------------------------|---------------|-----------|----------------------------|---------------|-----------|-------------------------|---------------| 
| 001734 |  33104 | December, 21 2013 06:52:00 | 0 |  33374 | January, 21 2014 08:19:00 |   31 |  33399 | December, 19 2014 11:48:00 |   332 |  34453 | March, 14 2015 09:14:00 |   84 | 
| 80592 |  27122 |  June, 26 2013 10:20:00 | 0 |  27248 | August, 01 2013 06:23:00 |   35 | (null) |      (null) |  (null) | (null) |     (null) |  (null) | 
| 35681 |  28153 | September, 14 2012 05:00:00 | 0 |  29007 | November, 16 2012 08:23:00 |   63 | (null) |      (null) |  (null) | (null) |     (null) |  (null) |