使用 t-sql 仅加入“最新”记录
Posted
技术标签:
【中文标题】使用 t-sql 仅加入“最新”记录【英文标题】:Join to only the "latest" record with t-sql 【发布时间】:2011-05-26 15:46:35 【问题描述】:我有两张桌子。表“B”与表“A”是一对多的关系,这意味着表“A”中的一条记录将有表“B”中的许多记录。
表“B”中的记录主要通过日期来区分,我需要生成一个结果集,其中包含表“A”中的记录以及表“B”中的最新记录.出于说明目的,这里有一个示例架构:
Table A
-------
ID
Table B
-------
ID
TableAID
RowDate
我在制定查询以向我提供我正在寻找的任何帮助的结果集时遇到问题。
【问题讨论】:
如果表B中的两行有相同的日期时间,你将如何定义单个最新记录?值得注意的是,DateTime 只能达到 3 毫秒(或类似的时间),而 DateTime2 可以测量到纳秒(因此更准确)。 将[Table A] 与[Table B] 连接的列是TableAID? 应该包括这个......你可以假设不会有重复的日期时间,所以总会有一个“最新的”:-) 【参考方案1】:SELECT *
FROM tableA A
OUTER APPLY (SELECT TOP 1 *
FROM tableB B
WHERE A.ID = B.TableAID
ORDER BY B.RowDate DESC) as B
【讨论】:
外部应用要快得多! 与我在系统上尝试的其他方法相比,外部应用速度非常快。 我刚刚测试了接受的答案与这个答案,我发现外部应用比接受的答案慢约 2 倍! @Maderas 在测试期间你不止一次地运行了它们,对吧?否则,数据可能已被缓存。 @DanielLorenz 我不记得了。我通常每个运行至少 5 次。我也倾向于在测试新东西之前重新启动我的开发服务器以了解它的性能,但是......我不记得了。【参考方案2】:select a.*, bm.MaxRowDate
from (
select TableAID, max(RowDate) as MaxRowDate
from TableB
group by TableAID
) bm
inner join TableA a on bm.TableAID = a.ID
如果您需要 TableB 中的更多列,请执行以下操作:
select a.*, b.* --use explicit columns rather than * here
from (
select TableAID, max(RowDate) as MaxRowDate
from TableB
group by TableAID
) bm
inner join TableB b on bm.TableAID = b.TableAID
and bm.MaxRowDate = b.RowDate
inner join TableA a on bm.TableAID = a.ID
【讨论】:
这并不能完全回答这个问题,因为它只从表 b 中获取最大行日期。该问题已询问最近的行 - 因此需要为该行返回表 b 的其余部分,并且还需要考虑表 B 具有两个相同日期/时间的条目作为 TableA 参考 @Paul:我假设 TableB 只有 OP 指定的字段。已修改查询以处理您提到的情况。重复对于用户的数据来说可能是也可能不是问题。 只是好奇......为什么要避免使用“*”?如果我真的想要结果集中的所有列,那么使用它有什么缺点? @Joel:避免 * 解决了以下问题:重复列、关于返回列顺序的假设、选择比您需要的更多数据的性能损失等等。【参考方案3】:With ABDateMap AS (
SELECT Max(RowDate) AS LastDate, TableAID FROM TableB GROUP BY TableAID
),
LatestBRow As (
SELECT MAX(ID) AS ID, TableAID FROM ABDateMap INNER JOIN TableB ON b.TableAID=a.ID AND b.RowDate = LastDate GROUP BY TableAID
)
SELECT columns
FROM TableA a
INNER JOIN LatestBRow m ON m.TableAID=a.ID
INNER JOIN TableB b on b.ID = m.ID
【讨论】:
【参考方案4】:表 B 连接是可选的:这取决于您是否需要其他列
SELECT
*
FROM
tableA A
JOIN
tableB B ON A.ID = B.TableAID
JOIN
(
SELECT Max(RowDate) AS MaxRowDate, TableAID
FROM tableB
GROUP BY TableAID
) foo ON B.TableAID = foo.TableAID AND B.RowDate= foo.MaxRowDate
【讨论】:
【参考方案5】:只是为了清楚起见,并使那些偶然发现这个古老问题的人受益。如果Table B
中有重复的RowDate
,则接受的答案将返回重复的行。更安全、更有效的方法是使用ROW_NUMBER()
:
Select a.*, b.* -- Use explicit column list rather than * here
From [Table A] a
Inner Join ( -- Use Left Join if the records missing from Table B are still required
Select *,
ROW_NUMBER() OVER (PARTITION BY TableAID ORDER BY RowDate DESC) As _RowNum
From [Table B]
) b
On b.TableAID = a.ID
Where b._RowNum = 1
【讨论】:
【参考方案6】:试试这个:
BEGIN
DECLARE @TB1 AS TABLE (ID INT, NAME VARCHAR(30) )
DECLARE @TB2 AS TABLE (ID INT, ID_TB1 INT, PRICE DECIMAL(18,2))
INSERT INTO @TB1 (ID, NAME) VALUES (1, 'PRODUCT X')
INSERT INTO @TB1 (ID, NAME) VALUES (2, 'PRODUCT Y')
INSERT INTO @TB2 (ID, ID_TB1, PRICE) VALUES (1, 1, 3.99)
INSERT INTO @TB2 (ID, ID_TB1, PRICE) VALUES (2, 1, 4.99)
INSERT INTO @TB2 (ID, ID_TB1, PRICE) VALUES (3, 1, 5.99)
INSERT INTO @TB2 (ID, ID_TB1, PRICE) VALUES (1, 2, 0.99)
INSERT INTO @TB2 (ID, ID_TB1, PRICE) VALUES (2, 2, 1.99)
INSERT INTO @TB2 (ID, ID_TB1, PRICE) VALUES (3, 2, 2.99)
SELECT A.ID, A.NAME, B.PRICE
FROM @TB1 A
INNER JOIN @TB2 B ON A.ID = B.ID_TB1 AND B.ID = (SELECT MAX(ID) FROM @TB2 WHERE ID_TB1 = A.ID)
END
【讨论】:
【参考方案7】:这将使用 JOIN 获取最新记录。我认为这会对某人有所帮助
SELECT cmp.*, lr_entry.lr_no FROM
(SELECT * FROM lr_entry ORDER BY id DESC LIMIT 1)
lr_entry JOIN companies as cmp ON cmp.id = lr_entry.company_id
【讨论】:
以上是关于使用 t-sql 仅加入“最新”记录的主要内容,如果未能解决你的问题,请参考以下文章