我有以下表格结构:
我无法使用左连接获得上述所需的输出:
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表可以为同一个键提供多个条目。但是如何让它只检查该密钥的最后一个条目?
所以我希望Key表中的所有记录在记录表中具有最后一条记录isSignedIn = 1。如果KeyRecords表中没有密钥记录,我仍然想要显示它。
答案 0 :(得分: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。
答案 1 :(得分: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
列的简单索引就足够了。
您可以从计划中看到,对于Key
表中的每一行,服务器在KeyRecords
表上执行一次索引查找。如果Key
表格很小且KeyRecords
很大,则整体效率非常高。