2010-12-16 17 views
16

Mam dwa stoły. Tabela "B" ma związek jeden do wielu z tabelą "A", co oznacza, że ​​będzie wiele rekordów w tabeli "B" dla jednego rekordu w tabeli "A".Dołącz tylko do "najnowszego" rekordu z t-sql

rekordów w tabeli „B” są zróżnicowane głównie w terminie, muszę produkować zestaw wyników, która zawiera rekord w tabeli „A” połączone tylko z rekordu w tabeli „B” najnowszy. W celu zilustrowania, oto przykładowy schemat:

Table A 
------- 
ID 

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

Mam problemy formułując zapytanie dać mi resultset szukam jakiejkolwiek pomocy byłoby bardzo mile widziane.

+0

W przypadku dwóch wierszy w tabeli B o takiej samej datetime, w jaki sposób można określić pojedynczy ostatni rekord? Warto zauważyć, że DateTime jest dobre tylko do 3ms (lub coś podobnego), podczas gdy DateTime2 może mierzyć do nanosekund (więc jest dokładniejsze). –

+0

Kolumna do przyłączenia [Tabela A] z [Tabelą B] to TableAID? – Lamak

+0

Powinienem załączyć to ... możesz założyć, że nie będzie duplikatów datetimes, więc zawsze będzie "najnowszy" :-) –

Odpowiedz

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 

Jeśli potrzebujesz więcej kolumn z TableB, to zrobić:

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

pokonać mnie przez kilka sekund :) – Randy

+1

To nie całkiem odpowiada na pytanie w pełni ponieważ dostaje tylko maksymalną datę z tabeli b. Pytanie dotyczyło ostatniego wiersza - więc reszta tabeli b musi zostać zwrócona dla tego wiersza, a także musi uwzględnić tabelę B mającą dwa wpisy o tej samej dacie/czasie dla odniesienia tabeliA –

+0

@Paul: założyłem TableB ma tylko określone pola według OP. Zmodyfikowano zapytanie, aby obsłużyć wspomniany przypadek. Duplikaty mogą, ale nie muszą być problemem dla danych użytkownika. – RedFilter

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

tabela B przyłączyć jest opcjonalne: to zależy, czy istnieją inne kolumny chcesz

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

zastosowanie zewnętrzne jest znacznie szybsze! –

+1

To, co zewnętrzne, działa błyskawicznie w porównaniu do innych metod, które wypróbowałem w moim systemie. –

+0

Właśnie przetestowałem zaakceptowaną odpowiedź w porównaniu z tą odpowiedzią i stwierdziłem, że zastosowanie zewnętrzne było ~ 2 razy wolniejsze niż przyjęta odpowiedź! – Maderas

0

Tylko dla jasności i dla korzyści tych, którzy się potkną w to starożytne pytanie. Zaakceptowana odpowiedź zwróci wiersze z duplikatami, jeśli istnieje duplikat RowDate w Table B. Bezpieczniejsze i bardziej wydajny sposób byłoby wykorzystać 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

Spróbuj użyć tego:

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