2010-07-07 17 views
5

Basit bir sorguya sahibim ve daha zarif kodlanmış olabileceğini merak ediyorum. Son çözüm ansi uyumlu olmalıdır.SQL ifadesi son tarih bilgisine göre en son veri değerini seç

En son değeri, tarih ve sürüme göre bir tablodan getirmem gerekiyor. Bir numune daha net açıklıyor:

declare @t table (id int, due_date smalldatetime, version int, value nvarchar(10)) 

insert into @t select 3, '1/1/2010', 1, 'value 1' 
insert into @t select 3, '1/1/2010', 2, 'value 2' 
insert into @t select 3, '3/1/2010', 1, 'value 3' 
insert into @t select 3, '3/1/2010', 2, 'value 4' 
insert into @t select 3, '3/1/2010', 3, 'value 5' 
insert into @t select 3, '3/1/2010', 4, 'value 6' 
insert into @t select 3, '4/1/2010', 1, 'value 7' 
insert into @t select 3, '4/1/2010', 2, 'value 8' 
insert into @t select 3, '4/1/2010', 3, 'value 9' 


select value from @t t 
    inner join (select due_date, version=max(version) 
       from @t where due_date = (select max(due_date) from @t) group by due_date) maxes 
    on t.due_date=maxes.due_date and t.version=maxes.version 

Yani çıkış yukarıdaki sorguya dayalı

value 9 

olması beklenebilir.

Bu çözümden özellikle memnun değilim - bunu başarmanın daha iyi yolları?

cevap

5

Sen kullanabilirsiniz:

SELECT TOP 1 
     x.value 
    FROM @t x 
ORDER BY x.due_date DESC, x.version DESC 

TOP olsa ANSI değildir. Başka bir seçenek ANSI analitik/rank/pencere fonksiyonlarını kullanmak olacaktır:

SELECT x.value 
    FROM (SELECT t.value, 
       ROW_NUMBER() OVER (ORDER BY t.due_date DESC, t.version DESC) AS rank 
      FROM @t t) x 
WHERE x.rank = 1 

Ama bu işlevi destekleyen bir veritabanı gerektirir - ... MySQL, PostgreSQL sadece V8.4 başlayan gelmez

+0

Haha, bu hatta aklımdan geçmedi kadar basit ... – cjk

+0

(yanıtları, yani). Daha önce sıralama fonksiyonlarını hiç kullanmamıştım - bence yüksek zaman öğrendim ... Cevaplar için teşekkürler. DÜZENLEME: SQL Server 2005 – Sean

+0

@Sean: Bu örnek için ROW_NUMBER önce TOP kullanmanızı veya Tom H'nin sorgularından birini kullanmayı öneririm. –

1
SELECT 
    value 
FROM 
    @t T1 
LEFT OUTER JOIN @t T2 ON 
    T2.id = T1.id AND 
    (
     (T2.due_date > T1.due_date) OR 
     (T2.due_date = T1.due_date AND T2.version > T1.version) 
    ) 
WHERE 
    T2.id IS NULL 
inanılmaz hızlı

ya ...

SELECT 
    value 
FROM 
    @t T1 
WHERE 
    NOT EXISTS 
    (
     SELECT 
     FROM 
      @t T2 
     WHERE 
      T2.id = T1.id AND 
      (
       (T2.due_date > T1.due_date) OR 
       (T2.due_date = T1.due_date AND T2.version > T1.version) 
      ) 
    )