2015-10-20 165 views
2

我有一个放射性肺结节事件的放射学报告数据库。每名患者都有一个医疗记录号,每个程序都有一个唯一的登录号。因此,MRN可以为不同的程序提供多个登录号。登记号码是递增的,所以如果患者有多个登录号码,最大的登录号码是最新的程序。我需要:SQL中的相关子查询

  • 找出最老的(最初的)研究
  • 查找该inital
  • 后谈到最快的一次研究,计算各区间

我相信这个问题之间的时间差可以使用相关的子查询来解决。但是,我还没有足够的SQL来解决这个问题。我试过自己加入表格并找到每个子查询的最大加入。下面的一些示例代码来制作数据集:

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") 

显然这是假数据。我一直在试图做的是用相关的子查询自己加入表格。像这样:

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 

理想是什么,我想是一个MRN对行和加入每位患者每个MRN为列(日期为种质等一起)主表。这样的事情:

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

我相信子查询我需要一系列左连接;不过,有没有更好的方法来做到这一点?有些患者随访7次以上。感谢任何帮助,对于长时间的解释感到抱歉。希望格式可以。

+0

你也可以包括工作www.SqlFiddle.com,这样才有利于测试的答案。 –

回答

1

你在正确的轨道上。你可以使用自连接和子查询来完成。该表应该与MRN1上的自身结合,并且后一记录的登录1等于该MRN1的最小登录1大于第一个记录(下一个MRN1)的MRN1。左连接允许查询报告所有记录,甚至最后一个(没有后继者)。

这个查询产生的所有对相邻的研究:

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) 

此查询生成前三研究:

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

嗨,查尔斯,谢谢你的回复。你的代码有效;但是,我希望MRN不会在行之间重复。相反,我希望将MRNs放在一行中,并将每个后续列作为列。在当前的代码中,如果一个人有4项研究,他们将在4个不同的行上。我试图在第一列中使用第一个(最老的研究)的一行MRN,并且每个研究在附加列中向右。谢谢。 –

+0

@david,这很难,它需要查询动态生成每行输出不同数量的列。 –

0

不知道,如果你希望所有的范围或仅仅是第2位。查尔斯查询我相信提供所有。

这只是前两个。

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

嗨胡安,你的例子适用于第一次后续研究。但是,如何添加更多的左连接以进行更多的后续操作?这段代码正是我第一次跟进所需要的,一行是MRN,最老的先行,然后是下一行。我想将每个后续行动增加到7左右。 –

+0

因此,您希望Charles和我的合并还是Charles查询的改进?你看过http://www.sqlfiddle.com/了吗?我尝试上传你的样本,但得到了错误sintaxis,没有时间修复它 –

+0

确实。添加这样的: 'AND neO2.Accession1 =(SELECT MIN(Accession1) FROM Four_mm_or_Less甲 WHERE A.MRN1 = O.MRN1 AND A.Accession1 <> O.Accession1 \t \t \t \t \t \t和A. Accession1 <> neO.Accession1)' 到脚本的最后一个代码会将其展开到下一个后续步骤,但不包括所有未进行2次跟进的情况。我试图仍然保留那些没有后续的MRN,但是没有后续的字段只有空值。 –

0

你可能想发表minimal working example,你的例子包括不需要的,使事情变得复杂很多列。

以下架构位于SQL Fiddle上,请参阅下文。我将Accession 34453的年份更改为2015,加入顺序和日期错误。

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")); 

集团的毗连历届之加入
看来你想有一个可变的列数,或动态创建这些列。据我所知,这是行不通的。正如其他答案中提出的,您必须为每列添加LEFT JOIN。但是,在MySQL中,您可以使用GROUP_CONCAT来连接组的值。您的值不再位于单个列中,但结果可能接近您的预期。

接下来生成两个后续日期之间的差异,在PostgreSQL中你有窗口函数来实现这一点。在MySQL中,您可以使用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; 

可能接近你正在寻找什么,Results SQL小提琴。

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

加入固定上加入的人数
下面的查询是相同的查询查尔斯BRETANA已经发布了。它加入了固定数量的种质。这个查询的缺点是,你没有得到最近的加入者,而是七/四个最古老的加入者。

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) 
; 

结果

| 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) |