2010-12-16 8 views
16

Tengo dos tablas. La Tabla "B" tiene una relación uno a muchos con la Tabla "A", lo que significa que habrá muchos registros en la tabla "B" para un registro en la tabla "A".Únase al registro "más reciente" con t-sql

Los registros en la tabla "B" se diferencian principalmente por una fecha, necesito producir un conjunto de resultados que incluya el registro en la tabla "A" junto con el último registro en la tabla "B". Para propósitos ilustrativos, aquí hay un esquema de ejemplo:

Table A 
------- 
ID 

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

Tengo problemas para la formulación de la consulta que me diera el conjunto de resultados que estoy buscando cualquier ayuda sería muy apreciada.

+0

En el caso de las dos filas de la tabla B que tiene la misma fecha y hora, ¿cómo va a definir el single más reciente ¿grabar? Vale la pena señalar que DateTime solo es bueno para 3 ms (o algo así), mientras que DateTime2 puede medir hasta nanosegundos (por lo que es más preciso). –

+0

La columna para unir [Tabla A] con [Tabla B] es TableAID? – Lamak

+0

Debería haber incluido esto ... puede suponer que no habrá fechas duplicadas, por lo que siempre habrá una "última" :-) –

Respuesta

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 

Si necesita más columnas de la Tabla B, hacer esto:

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

me ganó unos segundos :) – Randy

+1

Esto no responde completamente la pregunta ya que solo obtiene la fecha máxima de fila de la tabla b. La pregunta ha pedido la fila más reciente, por lo que el resto de la tabla b debe devolverse para esa fila y también debe tener en cuenta que la Tabla B tiene dos entradas de la misma fecha/hora para una referencia TableA –

+0

@Paul: asumí TableB solo tiene campos especificados por OP. Haber modificado la consulta para manejar el caso que menciona. Los duplicados pueden o no ser un problema para los datos del usuario. – 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

la tabla B se unen es opcional: depende si hay otras columnas que desea

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

exterior aplicar es mucho más rápido! –

+1

Esa aplicación externa es increíblemente rápida en comparación con otros enfoques que probé en mi sistema. –

+0

Acabo de probar la respuesta aceptada frente a esta respuesta y encontré que la aplicación externa era ~ 2 veces más lenta que la respuesta aceptada. – Maderas

0

Solo por el bien de la claridad y en beneficio de aquellos que tropezarán con upo n esta antigua pregunta. La respuesta aceptada devolvería filas duplicadas si hay duplicados RowDate en Table B. Una forma más segura y más eficiente sería utilizar 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

Trate de usar esto:

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 
Cuestiones relacionadas