SQL query - Join that returns the first two records of joining table

后端 未结 8 1728
陌清茗
陌清茗 2021-02-02 03:50

I have two tables:

Patient

  • pkPatientId
  • FirstName
  • Surname

PatientStatus

  • pk
相关标签:
8条回答
  • 2021-02-02 03:53

    Here is my attempt - It should work on SQL Server 2005 and SQL Server 2008 (Tested on SQL Server 2008) owing to the use of a common table expression:

    WITH CTE AS
    (
        SELECT  fkPatientId
              , StatusCode
              -- add more columns here
              , ROW_NUMBER() OVER
        (
        PARTITION BY fkPatientId ORDER BY fkPatientId desc) AS [Row_Number] 
        from PatientStatus
        where fkPatientId in
        (
            select fkPatientId
            from PatientStatus
            group by fkPatientId
            having COUNT(*) >= 2
        )
    )
    SELECT p.pkPatientId,
        p.FirstName,
        CTE.StatusCode  
    FROM [Patient] as p
        INNER JOIN CTE
            ON p.[pkPatientId] = CTE.fkPatientId
    WHERE CTE.[Row_Number] = 1 
    or CTE.[Row_Number] = 2
    
    0 讨论(0)
  • 2021-02-02 03:53

    I did not try but this could work;

    SELECT /*(your select columns here)*/, row_number() over(ORDER BY ps.fkPatientId, ps.StartDate) as rownumber FROM Patient p INNER JOIN PatientStatus ps ON p.pkPatientId = ps.fkPatientId
    where rownumber between 1 and 2
    

    if this did not work, see this link.

    0 讨论(0)
  • 2021-02-02 03:58

    A CTE is probably your best bet if you're in SQL Server 2005 or greater, but if you want something a little more compatible with other platforms, this should work:

    SELECT
         P.pkPatientID,
         P.FirstName,
         P.LastName,
         PS1.StatusCode AS FirstStatusCode,
         PS1.StartDate AS FirstStatusStartDate,
         PS1.EndDate AS FirstStatusEndDate,
         PS2.StatusCode AS SecondStatusCode,
         PS2.StartDate AS SecondStatusStartDate,
         PS2.EndDate AS SecondStatusEndDate
    FROM
         Patient P
    INNER JOIN PatientStatus PS1 ON
         PS1.fkPatientID = P.pkPatientID
    INNER JOIN PatientStatus PS2 ON
         PS2.fkPatientID = P.pkPatientID AND
         PS2.StartDate > PS1.StartDate
    LEFT OUTER JOIN PatientStatus PS3 ON
         PS3.fkPatientID = P.pkPatientID AND
         PS3.StartDate < PS1.StartDate
    LEFT OUTER JOIN PatientStatus PS4 ON
         PS4.fkPatientID = P.pkPatientID AND
         PS4.StartDate > PS1.StartDate AND
         PS4.StartDate < PS2.StartDate
    WHERE
         PS3.pkPatientStatusID IS NULL AND
         PS4.pkPatientStatusID IS NULL
    

    It does seem a little odd to me that you would want the first two statuses instead of the last two, but I'll assume that you know what you want.

    You can also use WHERE NOT EXISTS instead of the PS3 and PS4 joins if you get better performance with that.

    0 讨论(0)
  • 2021-02-02 03:59

    Ugly, but this one does not rely on uniqueness of StartDate and works on SQL 2000

    select * 
    from Patient p 
    join PatientStatus ps on p.pkPatientId=ps.fkPatientId
    where pkPatientStatusId in (
     select top 2 pkPatientStatusId 
     from PatientStatus 
     where fkPatientId=ps.fkPatientId 
     order by StartDate
    ) and pkPatientId in (
     select fkPatientId
     from PatientStatus
     group by fkPatientId
     having count(*)>=2
    )
    
    0 讨论(0)
  • 2021-02-02 04:03

    Check if your server supports windowed functions:

    SELECT * 
    FROM Patient p
    LEFT JOIN PatientStatus ps ON p.pkPatientId = ps.fkPatientId
    QUALIFY ROW_NUMBER() OVER (PARTITION BY ps.fkPatientId ORDER BY ps.StartDate) < 3
    

    Another possibility, which should work with SQL Server 2005:

    SELECT * FROM Patient p
    LEFT JOIN ( 
        SELECT *, ROW_NUMBER(PARTITION BY fsPatientId ORDER by StartDate) rn
        FROM PatientStatus) ps
    ON p.pkPatientId = ps.fkPatientID 
    and ps.rn < 3
    
    0 讨论(0)
  • 2021-02-02 04:09

    Adding this WHERE clause to the outer query of Tomalak's first solution will prevent Patients with less than 2 status records from being returned. You can also "and" it in the WHERE clause of the second query for the same results.

    WHERE pkPatientId IN (
        SELECT pkPatientID 
        FROM Patient JOIN PatientStatus ON pkPatientId = fkPatientId
        GROUP BY pkPatientID HAVING Count(*) >= 2
    )
    
    0 讨论(0)
提交回复
热议问题