2009-12-23 12 views
15

Aşağıdaki senaryoyu işlemek için bir yol arıyorum. Tabloda yer alan her "grup kimliği" için sadece bir kayıt döndürmek zorunda olduğum bir veritabanı tablom var, ayrıca her grupta seçilen kayıt hane içindeki en yaşlı kişi olmalıdır. her grubu kimliği olan eski insanlar Yani numarası 1 ve 3 gerekir I, yukarıda verilen örnek veriSQL sorgusu sadece grup kimliği başına 1 kayıt döndürmek için

ID Group ID Name    Age 
1 134  John Bowers  37 
2 134  Kerri Bowers  33 
3 135  John Bowers  44 
4 135  Shannon Bowers  42 

, geri döndü.

Bu, bir SQL Server 2005 veritabanına göre sorgulanmaktadır.

+0

Eğer adı istiyorsanız, en büyük yaşı olan> 1 kişiyseniz,> 1 satırını seçme şansınız var demektir. Bu durumda hangi adın da seçileceği konusunda kriterler oluşturmalısınız. –

+0

İyi nokta Chris. Soruyu biraz basitleştirmeye çalışıyordu, ama bu gibi delikler çıkardı :-) Aslında cinsiyet için başka bir alanım var, bu yüzden bir hane içindeki en yaşlı erkeği seçmek istiyorum. eğer erkek varsa, o zaman en yaşlı kadın. Aynı yaşta aynı evde iki erkek olması durumunda, kayıtların sadece 1'ini seçmem gerekiyor. Bu, kravat kesicisinin en düşük ID numarasına sahip kişi kadar basit bir şey üzerine kurulabilir. –

+1

Joe Celko'nun "Smart for Smarties" adlı mükemmel kitabının 21.4, "Extrema Functions" bölümündeki bu tür sorunların iyi bir tartışması var. Basit SELECTs ve INSERT'lerden daha zorlu bir şeye dönüşecek olursanız, bu kitabı kesinlikle tavsiye ederim. – shoover

cevap

21
SELECT t.* 
FROM (
     SELECT DISTINCT groupid 
     FROM mytable 
     ) mo 
CROSS APPLY 
     (
     SELECT TOP 1 * 
     FROM mytable mi 
     WHERE mi.groupid = mo.groupid 
     ORDER BY 
       age DESC 
     ) t 

veya bu:

SELECT * 
FROM (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn 
     FROM mytable 
     ) 
WHERE rn = 1 

Bu hatta bağları durumunda grup başına en fazla bir rekor dönecektir.

iki yöntemin performans karşılaştırmaları için bloguma bu makaleye bakın:

+0

+1: Evet, bağlantılarla ilgili yasal uyarılarımı unuttum. Çok meşgul savaşlar patlıyor. –

+0

Teşekkürler Quassnoi. ORDER By maddesindeki yaş sütununa ek olarak cinsiyet sütununu ekleyebildim ve aradığım sonuçları aldım! (Cinsiyet sütunu sadece ilk sorudan sonra bir yorumda tartışıldı) Çözümünüz mükemmel ve uyarlanabilir! –

+0

Takip eden soru. Bunlar 175 milyon kayıtla karşı karşıya gelecek. Bir veya diğer sorgu daha verimli mi? –

0
SELECT GroupID, Name, Age 
FROM table 
INNER JOIN 
(
SELECT GroupID, MAX(Age) AS OLDEST 
FROM table 
) AS OLDESTPEOPLE 
ON 
table.GroupID = OLDESTPEOPLE.GroupID 
AND 
table.Age = OLDESTPEOPLE.OLDEST 
3

Kullanım:

SELECT DISTINCT 
     t.groupid, 
     t.name 
    FROM TABLE t 
    JOIN (SELECT t.groupid, 
       MAX(t.age) 'max_age' 
      FROM TABLE t 
     GROUP BY t.groupid) x ON x.groupid = t.groupid 
          AND x.max_age = t.age 

Yani ne 2+ kişiyi varsa bir grup için aynı yaş? Doğum tarihinden ziyade doğum tarihini saklamak daha iyidir - her zaman sunum için doğum tarihini hesaplayabilirsiniz.

+0

Bağların sakının! – Quassnoi

0

bazı hanelerde iki veya daha fazla "eski" insanlar varsa bu

Select * From Table t 
Where Age = (Select Max(Age) 
      From Table 
      Where GroupId = t.GroupId) 

(varsayarak Grupiçin Ev eşanlamlısıdır) deneyin (Hepsi aynı yaşta ve her kimse yoktur daha eski), o zaman bu, hepsini rastgele değil, hepsini de verecektir.

Bu bir sorunsa, o gruptaki bir kişi için rasgele bir anahtar değeri döndürmek üzere başka bir alt sorgu eklemeniz gerekir.

Select * From Table t 
Where Id = 
    (Select Max(Id) Fom Table 
    Where GroupId = t.GroupId 
     And Age = 
     (Select(Max(Age) From Table 
      Where GroupId = t.GroupId))