2009-12-23 6 views
15

Szukam sposobu na obsłużenie następującego scenariusza. Mam tabelę bazy danych, której potrzebuję zwrócić tylko jeden rekord dla każdego "identyfikatora grupy", który jest zawarty w tabeli, ponadto rekord wybrany w ramach każdej grupy powinien być najstarszą osobą w gospodarstwie domowym.Zapytanie SQL zwracające tylko 1 rekord na identyfikator grupy

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 

Tak więc w przykładowych danych zamieszczonych wcześniej I musiałby ID 1 i 3 zwracane są one najstarsze ludzi w każdym identyfikatorem grupy.

Odbywa się to w odniesieniu do bazy danych SQL Server 2005.

+0

Jeśli chcesz nazwę, nadal możesz wybrać> 1 wiersz, jeśli masz> 1 osobę z najstarszym wiekiem. Powinieneś także ustalić kryteria wyboru nazwy również w tym przypadku. –

+0

Dobra racja Chris. Próbuje nieco uprościć to pytanie, ale to pozostawia takie dziury :-) Właściwie to mam inne pole dla płci, więc szukam wyboru najstarszego mężczyzny w domu. jeśli jest mężczyzna, to najstarsza kobieta. W przypadku, gdy w tym samym gospodarstwie domowym jest dwóch mężczyzn w tym samym wieku, muszę wybrać tylko jeden z zapisów. Może to być oparte na czymś tak prostym, jak osoba o najniższym numerze identyfikacyjnym dla wyłącznika wiązania. –

+1

Istnieje dobra dyskusja na temat tego rodzaju problemu w sekcji 21.4, "Extrema Functions", z doskonałej książki Joe Celko "SQL for Smarties". Jeśli masz zamiar borykać się z czymś trudniejszym niż proste WYBIERZ i WSTAWIĆ, bardzo polecam tę książkę. – shoover

Odpowiedz

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 

lub to:

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

ten powróci co najwyżej jeden rekord dla każdej grupy nawet w przypadku remisu.

Zobacz ten artykuł na moim blogu do porównań wyników obu metod:

+0

+1: Tak, zapomniałem mojego zrzeczenia się więzów. Zbyt zajęty pożarami. –

+0

Dzięki Quassnoi. Udało mi się dodać kolumnę płci dodaną do kolumny wieku w klauzuli ORDER By i uzyskać wyniki, których szukałem! (Kolumna płci była omawiana tylko w komentarzu po moim wstępnym pytaniu) Twoje rozwiązanie jest idealne i łatwe do dostosowania! –

+0

Kolejne pytanie. Będą one prowadzone przeciwko 175 milionom rekordów. Czy jedno lub drugie zapytanie jest bardziej wydajne? –

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

Zastosowanie:

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 

Więc co, jeśli istnieje 2+ ludziom w tym samym wieku dla grupy? Lepiej zapisać datę urodzin niż wiek - zawsze możesz obliczyć datę urodzin dla prezentacji.

+0

Uwaga na krawaty! – Quassnoi

0

Spróbuj to (zakładając Grupa jest synonimem domowe)

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

Jeśli istnieją dwa lub więcej „najstarsze” ludzie w pewnym gospodarstwie domowym (wszyscy są w tym samym wieku i nie ma nikt inny starsze), to zwróci je wszystkie, nie tylko losowe.

Jeśli jest to problem, należy dodać kolejną podkwerendę, aby zwrócić dowolną wartość klucza dla jednej osoby w tym zestawie.

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)) 
Powiązane problemy