SQL Server:LEFT OUTER JOIN,TOP 1选择最多一行

Jer*_*old 18 sql sql-server-2008

我基本上需要在2个表上进行左外连接(CarePlan和Referrals)问题是我需要最新的推荐如果它存在,如果它不存在则确定.

我有这两个查询1.加入CarePlan/Referral表 - 如果护理计划有多个推荐,或者根本没有推荐信息(左外连接),则创建重复的护理计划2.根据日期选择前1个推荐CarePlanId

我想结合这两个所以我抓住所有的护理计划和它的推荐,如果它存在,如果它 - 只采取最新的推荐

select * from CarePlan c //query 1
left outer join Referral r on 
r.CarePlanId = c.CarePlanId


select top 1 * from Referral r //query 2
where r.CarePlanId = '1'
order by ReferralDate desc
Run Code Online (Sandbox Code Playgroud)

编辑:

第一个查询给我这样的东西:

CarePlanID    ReferralId     ReferralDate
----------    ----------     ------------
1             1              05/15/12
2             NULL           NULL
1             2              05/10/12  //Old date, dont want this careplan
Run Code Online (Sandbox Code Playgroud)

第二个查询将为我提供最新日期的推荐

ReferralId    ReferralDate
----------    ------------
1             05/15/12
Run Code Online (Sandbox Code Playgroud)

推荐数据可能有0个或更多属于Careplan的推荐

ReferralID  CarePlanId    Date
----------  ----------    ----
1           1             05/15/12
2           1             05/10/12
Run Code Online (Sandbox Code Playgroud)

最终,我想要一个查询,为我提供具有最新日期的推荐的careplans,如果它没有它,则为引用无效

像这样:

CarePlanId   ReferralId    ReferralDate
----------   ----------    ------------
1            1             05/15/12
2            NULL          NULL
Run Code Online (Sandbox Code Playgroud)

谢谢 - 我希望这是有道理的

usr*_*usr 45

select *
from CarePlan c
outer apply (
    select top 1 * --top N rows
    from Referral r
    where r.CarePlanId = c.CarePlanId --join condition
    order by /*fill this in!*/
) x
Run Code Online (Sandbox Code Playgroud)

请注意,由于优化程序的弱点(包括2014版),这会强制循环连接.


Cha*_*pra 8

我知道这个问题比较老,但我认为还有另一种方法未得到充分利用:

您可以将表连接回自己并使用运算符来查找"最新"记录.

回答

SELECT CP.CarePlanId, R.ReferralId, R.ReferralDate
FROM CarePlan CP
LEFT OUTER JOIN Referral R ON R.CarePlanId = CP.CarePlanId
LEFT OUTER JOIN Referral R_NEWER ON R.CarePlanId = R_NEWER.CarePlanId AND R.ReferralDate < R_NEWER.ReferralDate
WHERE R_NEWER.ReferralId IS NULL
Run Code Online (Sandbox Code Playgroud)

结果:

CP.CarePlanId   R.ReferralId    R.ReferralDate
----------      ----------      ------------
1               1               05/15/12
2               NULL            NULL
Run Code Online (Sandbox Code Playgroud)

说明

让我们打破这个.您基本上是说,对于每个推荐记录,(左外部)加入与相同CarePlanId相关联的每个其他推荐记录,但仅限于有较新的ReferralDate.

这是没有where子句的查询(以及来自R_NEWER表的一些附加信息):

SELECT CP.CarePlanId, R.ReferralId, R.ReferralDate, R_NEWER.ReferralId, R.NEWER.ReferralDate
FROM CarePlan CP
LEFT OUTER JOIN Referral R ON R.CarePlanId = CP.CarePlanId
LEFT OUTER JOIN Referral R_NEWER ON R.CarePlanId = R_NEWER.CarePlanId AND R.ReferralDate < R_NEWER.ReferralDate
Run Code Online (Sandbox Code Playgroud)

以下是该查询的结果:

CP.CarePlanId   R.ReferralId    R.ReferralDate  R_NEWER.ReferralId  R_NEWER.ReferralDate
----------      ----------      ------------    ------------        ------------    
1               1               05/15/12        NULL                NULL
2               NULL            NULL            NULL                NULL
1               2               05/10/12        1                   05/15/12
Run Code Online (Sandbox Code Playgroud)

如您所见,只有推荐ID 2(上面的第3条记录)找到了一个"更新"的记录才能加入推荐表(即推荐ID 1).推荐标识1(上面的第一条记录)没有找到"更新"的推荐(针对相同的CarePlanId).

所以,考虑到这一点,现在我们只需添加where子句:

SELECT CP.CarePlanId, R.ReferralId, R.ReferralDate, R_NEWER.ReferralId, R.NEWER.ReferralDate
FROM CarePlan CP
LEFT OUTER JOIN Referral R ON R.CarePlanId = CP.CarePlanId
LEFT OUTER JOIN Referral R_NEWER ON R.CarePlanId = R_NEWER.CarePlanId AND R.ReferralDate < R_NEWER.ReferralDate
WHERE R_NEWER.ReferralId IS NULL
Run Code Online (Sandbox Code Playgroud)

得到:

CP.CarePlanId   R.ReferralId    R.ReferralDate  R_NEWER.ReferralId  R_NEWER.ReferralDate
----------      ----------      ------------    ------------        ------------    
1               1               05/15/12        NULL                NULL
2               NULL            NULL            NULL                NULL
Run Code Online (Sandbox Code Playgroud)

此时,只需从SELECT中删除您的R_NEWER列,因为它们不再需要,您就可以得到答案.

重要的是要记住,在发生连接之后应用"where",但ON语句在连接时发生.为了让我更容易理解,我总是尝试编写SELECT和JOIN并从我加入的每个表中返回列,然后在我清楚了解返回的内容后添加我的WHERE子句.

警告 这种方法在大多数情况下都很有用,但如果您有2个推荐(对于相同的CarePlanId)且日期为05/15/12并且该日期是"最新的",则可能会有重复的行.要解决这个问题,如果出现这种情况,您可以根据"最高"的ReferralId扩展您的联接.