2009-04-09 13 views
6

He heredado una mesa con una estructura algo como esto:Seleccionar mayoría de los Estados Recientes De la Tabla Historia

ID Name Timestamp Data 
---------------------------- 
1 A  40   ... 
2 A  30   ... 
3 A  20   ... 
4 B  40   ... 
5 B  20   ... 
6 C  30   ... 
7 C  20   ... 
8 C  10   ... 

ID es un campo de identidad y la clave principal y hay índices no únicos en el Name y Timestamp campos.

¿Cuál es la forma más eficiente para obtener el registro más reciente para cada nombre del elemento, es decir, en la tabla anterior filas , y deben ser devueltos ya que son los más actualizada entradas de fecha para los artículos A, B y C respectivamente.

Respuesta

13

SQL Server 2005 (en adelante):

WITH MostRecentRows AS 
(
    SELECT ID, Name, Data, 
    ROW_NUMBER() OVER (PARTITION BY Name ORDER BY TimeStamp DESC) AS 'RowNumber' 
    FROM MySchema.MyTable 
) 
SELECT * FROM MostRecentRows 
WHERE RowNumber = 1 
+0

+1 exactamente lo que estaba pensando así. – Sung

+0

Huh. +1. Lo hice funcionar, pero no podría decir si 'MostRecentRows',' Row_Number() ', o' PARTITION' está haciendo la magia. – jp2code

+0

Exactamente lo que estaba buscando – arjun

5

Asumiendo que no hay marcas de tiempo duplicados por nombre, algo como esto debería funcionar:

SELECT ID, Name, Timestamp, Data 
FROM test AS o 
WHERE o.Timestamp = (SELECT MAX(Timestamp) 
        FROM test as i 
        WHERE i.name = o.name) 
+0

+1 para las subconsultas correlacionadas – Sung

+2

Sí, esto solo funcionaría si no hay marcas de tiempo duplicadas. La descripción de CTE es definitivamente más segura ya que solo devolverá una fila. –

3

SQL Server 2000:

SELECT 
    ID, Name, Timestamp, Data 
FROM 
    DataTable 
    INNER JOIN 
    (
    SELECT ID, MAX(Timestamp) Timestamp FROM DataTable GROUP BY ID 
) latest ON 
    DataTable.ID = Latest.ID AND 
    DataTable.Timestamp = Latest.Timestamp 
+0

+1 para una solución alternativa de SQL Server 2000 – Sung

+0

Esto podría devolver más de un registro si hay registros múltiples para una marca de tiempo. –

+0

Soy perfectamente consciente de este hecho. Una cláusula GROUP BY externa adicional migra este riesgo, en caso de que sea posible duplicar las marcas de tiempo. – Tomalak

0

Si está utilizando SQL Server 2005/2008, entonces la solución CTE que ya mencionó Mitch Weat es la mejor de una perspectiva de rendimiento. Sin embargo, si está utilizando SQL Server 2000, entonces no puede suponer que no hay nombres duplicados | Combinaciones de TimeStamp Utilice el siguiente código para devolver sólo un registro por nombre:

SELECT ID 
    , Name 
    , TimeStamp 
    , Data 
FROM DataTable dt 
INNER JOIN 
    (SELECT Name 
    , MIN(DataTable.ID) AS MinimumID 
FROM DataTable 
INNER JOIN 
    (SELECT Name 
     , MAX(Timestamp) AS Timestamp 
    FROM DataTable 
    GROUP BY Name) latest 
    ON DataTable.Name = Latest.Name 
    AND DataTable.Timestamp = Latest.Timestamp 
GROUP BY Name) MinimumLatest 
ON dt.ID = MinimumLatest.ID 

Así que si se agrega otro disco como 9 C 30, entonces esto sólo devolverá ID 6. Si no ir tan lejos, entonces usted puede terminan de retorno 9 C 30 y C 30. 6

0

Otra manera fácil:

SELECT ID,Name,Timestamp, Data 
FROM Test_Most_Recent 
WHERE Timestamp = (SELECT MAX(Timestamp) 
       FROM Test_Most_Recent 
       group by Name); 
Cuestiones relacionadas