2010-12-16 50 views
16

我有两张桌子。表“B”与表“A”具有一对多关系,这意味着表“A”中的一条记录在表“B”中将有许多记录。加入到t-sql的“最新”记录

表“B”的记载主要是由一个日期来区分,我需要产生一个结果,其中包括在表中的“A”加入了只有在表“B”的最新记录备案。为了说明目的,这里有一个示例模式:

Table A 
------- 
ID 

Table B 
------- 
ID 
TableAID 
RowDate 

我在遇到麻烦时制定所述查询给我我正在寻找任何帮助的结果集将不胜感激。

+0

在具有相同的datetime表B两行的情况下,你会如何定义一个最新记录?值得注意的是,DateTime只有3毫秒(或类似的东西),而DateTime2可以测量到纳秒(所以更准确)。 – 2010-12-16 16:15:20

+0

要将[Table A]加入[Table B]的列是TableAID? – Lamak 2010-12-16 16:16:27

+0

应该包括这个......你可以假设不会有重复的日期时间,所以总会有一个“最新的”:-) – 2010-12-16 18:07:33

回答

23
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 

如果从表B需要更多的列,这样做:

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.TableA = b.TableA 
    and bm.MaxRowDate = b.MaxRowDate 
inner join TableA a on bm.TableAID = a.ID 
+0

打我几秒:) – Randy 2010-12-16 16:14:52

+1

这并不完全回答这个问题因为它只能从表b得到最大行数。该问题要求提供最近的一行 - 因此需要为该行返回表b的其余部分,并且还需要考虑表B具有两个相同日期/时间的条目以用于TableA引用 – 2010-12-16 16:18:50

+0

@Paul:我假设表B仅由OP指定了字段。修改了查询以处理您提到的情况。重复可能会或可能不会成为用户数据的问题。 – RedFilter 2010-12-16 16:22:55

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 
2

表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 
24
SELECT * 
FROM tableA A 
OUTER APPLY (SELECT TOP 1 * 
      FROM tableB B 
      WHERE A.ID = B.TableAID 
      ORDER BY B.RowDate DESC) as B 
+1

外套更快! – 2015-05-08 01:12:50

+1

与我在我的系统上尝试过的其他方法相比,外层应用程序非常快。 – 2016-02-29 17:12:26

+0

我刚刚测试了接受的答案和这个答案,我发现外面的应用比接受的答案慢了2倍! – Maderas 2017-03-07 16:46:16

0

只是为了清晰起见,并为那些将蹒跚而行的人这个古老的问题。如果在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 
0

尝试使用这样的:

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