2015-03-19 40 views
1

我有以下表结构加入:SQL留下了重复

enter image description here

我只是无法获得所需要的输出如上使用左连接:

SELECT K.[ID], 
     K.[KeyName], 
     K.Notes, 
     KR.isSignedIn 
    FROM [dbo].[Keys] K 
    LEFT JOIN 
      [dbo].[KeyRecords] KR WITH(NOLOCK) 
    ON 
    K.ID = KR.Key_ID 
    WHERE 
     (KR.isSignedIn = 1 OR KR.isSignedIn is null) 

我知道原因,这是因为KeyRecords表可以有多个相同键的条目。但是,如何使它只检查该密钥的最后一项?

所以我想要记录表中最后一条记录isSignedIn = 1的Key表中的所有记录。如果KeyRecords表中没有记录,我仍然想要显示它。

+1

您必须获取全部3条记录,这是因为'keyId = 1'的isSignedIn'为1。如果你想忽略它,那么应该在那里有明显的区别,或者明确地将它排除在“where”之下 – Vikrant 2015-03-19 09:46:43

回答

0

这不是最好的解决方案,但这是诀窍。
我不知道你的表有多大,或者你有什么索引。

select 
    k.ID, k.KeyName, K.Notes, KR.isSignedIn 
from dbo.[Key] K 
left join dbo.[KeyRecords] KR 
    on kr.Key_ID = k.ID 
where (
     select MAX(ID) 
     from dbo.[KeyRecords] sub 
     where sub.Key_ID = kr.Key_ID 
    ) = 
     (
     select ID 
     from dbo.[KeyRecords] sub 
     where sub.Key_ID = kr.Key_ID 
     and sub.isSignedIn = 1 
    ) 
or kr.ID is null 

请检查SQLFiddle

0

当你需要 “一键最后一个条目” 使用CROSS or OUTER APPLY

WITH 
CTE 
AS 
(
    SELECT * 
    FROM 
    dbo.[Key] AS K 
    OUTER APPLY 
    (
     SELECT TOP(1) KeyRecords.isSignedIn 
     FROM KeyRecords 
     WHERE KeyRecords.Key_ID = K.ID 
     ORDER BY KeyRecords.ID DESC 
    ) AS A 
) 
SELECT * 
FROM CTE 
WHERE isSignedIn = 1 OR isSignedIn IS NULL 
ORDER BY ID 

这里是SQLFiddle

什么CTE这样做:对于每个Key查找KeyRecord中最大的行ID。 (如果这样的行不存在,返回NULL,所以我们需要OUTER APPLY这里)。

然后过滤结果并删除那些有isSignedIn = 0

如果您有小表或索引KeyRecords(Key_ID, ID),此变体将有效地工作。很有可能你的主键已经在ID上,所以Key_ID的简单索引与isSignedIn作为包含列应该就足够了。

Execution plan

您可以从计划,在Key表中每一行的服务器确实一个索引上KeyRecords表寻求见。如果Key表很小,并且KeyRecords很大,则整体效率非常高。