查找结果集中的最新日期

时间:2016-04-25 19:26:18

标签: sql sql-server group-by max where-clause

我正在进行查询,我需要查看患者访问诊所时输入的患者生命体征(特别是血压)。我在2015年全年都取得了成绩,当然有一些患者多次访问,我只需要看到最近访问时输入的生命体征。另一个轻微的转折是单独输入收缩压和舒张压,所以我得到的结果如下:

Patient ID     Name           DOB          Test              Results       Date
---------------------------------------------------------------------------------
1000           John Smith     1/1/1955     BP - Diastolic    120           2/10/2015
1000           John Smith     1/1/1955     BP - Systolic     70            2/10/2015
1000           John Smith     1/1/1955     BP - Diastolic    128           7/12/2015
1000           John Smith     1/1/1955     BP - Systolic     75            7/12/2015
1000           John Smith     1/1/1955     BP - Diastolic    130           10/22/2015
1000           John Smith     1/1/1955     BP - Systolic     76            10/22/2015
9999           Jane Doe       5/4/1970     BP - Diastolic    130           4/2/2015
9999           Jane Doe       5/4/1970     BP - Systolic     60            4/2/2015
9999           Jane Doe       5/4/1970     BP - Diastolic    127           11/20/2015
9999           Jane Doe       5/4/1970     BP - Systolic     65            11/20/2015

有26,000多个结果,所以显然我不想通过每个病人,看看他们最近的结果是什么时候。我希望我的结果看起来像这样:

Patient ID     Name           DOB          Test         Results       Date
---------------------------------------------------------------------------------
1000           John Smith     1/1/1955     BP - Diastolic    130           10/22/2015
1000           John Smith     1/1/1955     BP - Systolic     76            10/22/2015
9999           Jane Doe       5/4/1970     BP - Diastolic    127           11/20/2015
9999           Jane Doe       5/4/1970     BP - Systolic     65            11/20/2015

我知道出生的名字和出生日期以及不会重复的内容,但我主要关注结果栏。

这是我的疑问:

SELECT DISTINCT
    pd.PatientID as [Patient ID],
    pd.PatientName as Name,
    pd.DateOfBirth as DOB,
    v.Test as Test,
    v.Results as Results,
    v.TestDate as Date

FROM PatientDemographic pd JOIN Vitals v ON pd.PatientID = v.PatientID

WHERE v.TestDate BETWEEN '01/01/2015' AND '12/31/2015'
    AND v.Test LIKE 'BP%'

ORDER BY pd.PatientID, v.TestDate

在寻找其他答案后,我尝试为GROUP BY语句中的MAX()列执行v.TestDateSELECT聚合函数(我特意引用{ {3}},虽然它适用于Oracle而我使用的是SQL Server,所以我不完全确定语法是否相同)。我的查询看起来像:

SELECT DISTINCT
    pd.PatientID as [Patient ID],
    pd.PatientName as Name,
    pd.DateOfBirth as DOB,
    v.Test as Test,
    v.Results as Results,
    MAX(v.TestDate) as Date

FROM PatientDemographic pd JOIN Vitals v ON pd.PatientID = v.PatientID

WHERE v.TestDate BETWEEN '01/01/2015' AND '12/31/2015'
    AND v.Test LIKE 'BP%'

GROUP BY pd.PatientID

不可否认,我使用GROUP BY时总是有点挣扎。在这种特殊情况下,我得到一个错误,指出我需要将Patient Name列添加到GROUP BY子句中,所以我这样做,然后它要求DOB。然后测试名称。基本上,它希望我将SELECT语句中的所有内容添加到GROUP BY

进行最近的病人访问的最佳方式是什么?

5 个答案:

答案 0 :(得分:4)

一种简单方法使用ROW_NUMBER()查找每个测试的最新记录:

SELECT pd.PatientID as [Patient ID], pd.PatientName as Name, pd.DateOfBirth as DOB,
       v.Test as Test, v.Results as Results, v.TestDate as Date
FROM PatientDemographic pd JOIN
     (SELECT v.*,
             ROW_NUMBER() OVER (PARTITION BY PatientId, Test ORDER BY TestDate DESC) as seqnum
      FROM Vitals v
      WHERE v.TestDate BETWEEN '2015-01-01' AND '2015-12-31' AND
            v.Test LIKE 'BP%'
     ) v
     ON pd.PatientID = v.PatientID 
WHERE seqnum = 1
ORDER BY pd.PatientID, v.TestDate;

答案 1 :(得分:1)

我回避戈登使用的窗口功能。使用子查询的技术也可以完成工作:

Dim Filename 
Dim Connection 
Dim commandoSQL 
Dim Archivo 
Dim Nombre 
Dim objFSO 
Dim outputFile 

Call Main
Sub Main
    Set objFSO=CreateObject("Scripting.FileSystemObject")
    Call startConnection()  Set commandoSQL = Connection.Execute("select rest_def.obj_num, hdr_def.line_01, hdr_def.line_02, hdr_def.line_03, hdr_def.line_04, hdr_def.line_05, hdr_def.line_06, trlr_def.line_01, trlr_def.line_02, trlr_def.line_03, trlr_def.line_04, trlr_def.line_05, trlr_def.line_06, trlr_def.line_07, trlr_def.line_08, trlr_def.line_09, trlr_def.line_10, trlr_def.line_11, trlr_def.line_12 from rest_def inner join hdr_def on hdr_def.obj_num rest_def.obj_num inner join trlr_def on trlr_def.obj_num = hdr_def.obj_num where hdr_def.obj_num = 101")
    'Archivo = "D:\archives\"
    Set Filename = Connection.Execute("Select obj_num FROM rest_def")
    Nombre = Filename.getString
    Archivo = "D:\archives\" + Nombre + ".txt"
    Set outputFile = objFSO.CreateTextFile(Archivo,True)
    outputFile.Write commandoSQL & vbCrLf
    outputFile.Close
    Call closeConnection()
End Sub

Sub startConnection()
    Set Connection = WScript.CreateObject("ADODB.Connection")
    Connection.Open "DSN=milo; UID=dataBase; PWD=password"
End Sub

Sub closeConnection()
    Connection.Close 
End Sub

答案 2 :(得分:1)

这适用于MS SQL 2005+

SELECT * FROM (
SELECT row_number() over(partition by pd.PatientID, v.Test order by v.TestDate desc) as rn,
    pd.PatientID as [Patient ID],
    pd.PatientName as Name,
    pd.DateOfBirth as DOB,
    v.Test as Test,
    v.Results as Results,
    v.TestDate as Date
FROM PatientDemographic pd 
JOIN Vitals v ON pd.PatientID = v.PatientID
WHERE v.TestDate BETWEEN '01/01/2015' AND '12/31/2015'
    AND v.Test LIKE 'BP%') t
WHERE rn = 1

答案 3 :(得分:1)

窗口函数不如NOT EXISTS子句有效。我想提出一个不使用窗口函数的更快的解决方案:

SELECT 
    pd.PatientID as [Patient ID],
    pd.PatientName as Name,
    pd.DateOfBirth as DOB,
    v.Test as Test,
    v.Results as Results,
    v.TestDate as Date
FROM PatientDemographic pd JOIN Vitals v ON pd.PatientID = v.PatientID
WHERE 
    v.TestDate BETWEEN '01/01/2015' AND '12/31/2015'
    AND v.Test LIKE 'BP%'
    AND NOT EXISTS (
       SELECT 1 FROM Vitals as v2 where v2.PatientID = v.PatientID
       AND V2.TestDate BETWEEN '01/01/2015' AND '12/31/2015' 
       AND v2.Test LIKE 'BP%' 
       AND v2.TestDate > v.TestDate)

答案 4 :(得分:1)

您也可以使用Common Table Expression来实现此目的。

        IF OBJECT_ID('tempdb..#RecentPatientVitals') IS NOT NULL
        DROP TABLE #RecentPatientVitals;
    GO

    CREATE TABLE #RecentPatientVitals
        (
          Patient_ID INT
        , Name VARCHAR(100)
        , DOB DATE
        , Test VARCHAR(150)
        , Results INT
        , [Date] DATE
        );

    INSERT  INTO #RecentPatientVitals
            ( Patient_ID, Name, DOB, Test, Results, [Date] )
    VALUES  ( 1000, 'John Smith', '1/1/1955', 'BP - Diastolic', 120, '2/10/2015' )
    ,       ( 1000, 'John Smith', '1/1/1955', 'BP - Systolic', 70, '2/10/2015' )
    ,       ( 1000, 'John Smith', '1/1/1955', 'BP - Diastolic', 128, '7/12/2015' )
    ,       ( 1000, 'John Smith', '1/1/1955', 'BP - Systolic', 75, '7/12/2015' )
    ,       ( 1000, 'John Smith', '1/1/1955', 'BP - Diastolic', 130, '10/22/2015' )
    ,       ( 1000, 'John Smith', '1/1/1955', 'BP - Systolic', 76, '10/22/2015' )
    ,       ( 9999, 'Jane Doe', '5/4/1970', 'BP - Diastolic', 130, '4/2/2015' )
    ,       ( 9999, 'Jane Doe', '5/4/1970', 'BP - Systolic', 60, '4/2/2015' )
    ,       ( 9999, 'Jane Doe', '5/4/1970', 'BP - Diastolic', 127, '11/20/2015' )
    ,       ( 9999, 'Jane Doe', '5/4/1970', 'BP - Systolic', 65, '11/20/2015' );

    SELECT  *
    FROM    #RecentPatientVitals;

    WITH    PatVitals1
              AS ( SELECT   Patient_ID
                          , Name
                          , DOB
                          , Test
                          , MAX(Date) AS Date
                   FROM     #RecentPatientVitals
                   GROUP BY Patient_ID
                          , Name
                          , DOB
                          , Test
                 ) ,
            PatVitals2
              AS ( SELECT   Patient_ID
                          , Test
                          , Results
                          , Date
                   FROM     #RecentPatientVitals
                 )
        SELECT  P1.Patient_ID
              , P1.Name
              , P1.DOB
              , P1.Test
              , P2.Results
              , P1.Date
        FROM    PatVitals1 P1
                INNER JOIN PatVitals2 P2
                ON P2.Patient_ID = P1.Patient_ID
                   AND P2.Date = P1.Date
                   AND P2.Test = P1.Test
        GROUP BY P1.Patient_ID
              , P1.Name
              , P1.DOB
              , P1.Test
              , P2.Results
              , P1.Date;