2009-04-09 3 views
6

Ho ereditato un tavolo con un qualcosa di struttura come questa:Selezionare La maggior parte dei membri recenti Dalla Tabella Storia

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 è un campo di identità e la chiave primaria e ci sono gli indici non univoci sulla Name e Timestamp campi.

Qual è il modo più efficace per ottenere il record più recente per ogni nome di oggetto, vale a dire nella tabella sopra le righe , e dovrebbe essere restituito in quanto sono i più up-to voci di data per gli articoli A, B e C rispettivamente.

risposta

13

SQL Server 2005 (poi):

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 esattamente quello che stavo pensando pure. – Sung

+0

Huh. +1. Ho fatto in modo che funzioni, ma non potrei dirti se 'MostRecentRows',' Row_Number() ', o' PARTITION' sta facendo la magia. – jp2code

+0

Esattamente quello che stavo cercando – arjun

5

Supponendo non ci sono timestamp duplicati per nome, qualcosa di simile dovrebbe funzionare:

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 per subquery correlate – Sung

+2

Sì, ciò funzionerebbe solo se non vi sono timestamp duplicati. La descrizione CTE è sicuramente più sicura poiché restituirà solo una riga. –

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 per una soluzione SQL Server 2000 alternativa – Sung

+0

Ciò potrebbe restituire più di un record se sono presenti più record per un timestamp. –

+0

Sono perfettamente consapevole di questo fatto. Un'ulteriore clausola GROUP BY esterna migra questo rischio, dovrebbe essere possibile duplicare i timestamp. – Tomalak

0

Se si utilizza SQL Server 2005/2008, la soluzione CTE già elencata da Mitch Weat è la migliore da una prospettiva di prestazione. Tuttavia, se si utilizza SQL Server 2000, non si può presumere che non vi siano nomi duplicati | Combinazioni TimeStamp. Utilizzare il seguente codice per restituire solo un record per nome:

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 

Quindi, se si aggiunge un altro record come 9 C 30, allora questo restituisce solo ID 6. Se non si va a questo punto, allora si può finire ritorno 9 C 30 e C 6 30.

0

Un altro modo semplice:

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