2009-06-18 11 views
6

To, co mam, jest w zasadzie problemem, który można łatwo rozwiązać za pomocą wielu tabel, ale mam do tego tylko jedną tabelę.SQL - SELECT MAX() i towarzyszące mu pole

Rozważmy następującą tabelę bazy danych

UserID UserName EmailAddress   Source 
3K3S9 Ben  [email protected]  user 
SF13F Harry [email protected] 3rd_party 
SF13F Harry [email protected] user 
76DSA Lisa  [email protected]  user 
OL39F Nick  [email protected] 3rd_party 
8F66S Stan  [email protected]  user 

muszę zaznaczyć wszystkie pola, ale tylko każdy użytkownik raz wraz z jednym ze swoich adresów e-mail („największe” jednym, określonym przez Max (funkcja kto)). Jest to wynik jestem po ...

UserID UserName EmailAddress   Source 
3K3S9 Ben  [email protected]  user 
SF13F Harry [email protected] 3rd_party 
76DSA Lisa  [email protected]  user 
OL39F Nick  [email protected] 3rd_party 
8F66S Stan  [email protected]  user 

Jak widać, „Harry” pojawia się tylko raz z jego „najwyższy” adres email correcponding „źródło”

Obecnie co się dzieje jest że grupujemy się na UserID, UserName i używając MAX() dla EmailAddress i Source, ale maksimum tych dwóch pól nie zawsze się zgadza, muszą być z tego samego rekordu.

Próbowałem innego procesu, dołączając do samej tabeli, ale udało mi się uzyskać tylko prawidłowy adres e-mail, ale nie odpowiednie "źródło" dla tego adresu.

Każda pomoc będzie mile widziane jak spędziłem zbyt długo stara się rozwiązać ten już :)

+0

Czy masz dodatkową kolumnę z określonym kluczem podstawowym? Czy para (UserId, EmailAddress) jest unikalna? –

Odpowiedz

7

Jeśli jesteś na SQL Server 2005 lub wyższym,

SELECT UserID, UserName, EmailAddress, Source 
FROM (SELECT UserID, UserName, EmailAddress, Source, 
       ROW_NUMBER() OVER (PARTITION BY UserID 
            ORDER BY EmailAddress DESC) 
        AS RowNumber 
     FROM MyTable) AS a 
WHERE a.RowNumber = 1 

Oczywiście istnieją sposoby na wykonanie tego samego zadania bez funkcji (standardu SQL), takich jak ROW_NUMBER, które SQL Server zaimplementował dopiero od 2005 r. - włącznie z zagnieżdżonymi zapytaniami zależnymi i samodzielnymi lewymi połączeniami z ON, w tym ">" i WHERE ... IS NULL trick - ale funkcje rankingu sprawiają, że kod jest czytelny i (teoretycznie) dobrze zoptymalizowany przez silnik SQL Server.

Edit: this article jest ładny samouczek na ranking, ale korzysta RANK w przykładach zamiast ROW_NUMBER (lub inna funkcja rankingu DENSE_RANK) - rozróżnienie ma znaczenie, gdy istnieją „więzi” między wierszami zgrupowanych w tym samym podział według kryteriów zamówienia. this post wykonuje dobrą robotę wyjaśniając różnicę.

+0

Bardzo interesujący Alex, będę się uczyć o tych funkcjach. – tekBlues

+0

To z pewnością działa bardzo dobrze ... ale nie rozumiem składni>. Nippysaurus

+0

Edytowałem moją odpowiedź, aby dodać adresy URL do dwóch dobrych, krótkich samouczków dotyczących funkcji rankingowych - HTH! –

5
select distinct * from table t1 
where EmailAddress = 
(select max(EmailAddress) from table t2 
where t1.userId = t2.userId) 
+0

Warto zauważyć, że często może to działać szybciej niż zaakceptowana odpowiedź, szczególnie jeśli istnieje indeks {userid, EmailAddress DESC} na t2 –

0
select distinct 
    * 
from  
    SomeTable a 
inner join (
    select max(emailAddress), userId 
    from 
    SomeTable 
    group by 
    userId 
) b on a.emailAddress = b.emailAddress and a.userId = b.userId 
+0

Byłbym szczęśliwszy gdyby warunek ON zawierał a.userID = b.userID oraz adres e-mail. –

+0

To prawda, że ​​czyni to bardziej szczegółowym i pozwala uniknąć potencjalnych problemów. Zmieniłem moją odpowiedź, aby to odzwierciedlić. –

0

Chyba mam rozwiązanie, które różnią się od tych zaproponowanych już:

 
select * 
from foo 
where id = (
    select id 
    from foo F 
    where F.bar = foo.bar 
    order by F.baz 
    limit 1 
) 

To daje wszystkie rekordy foo, które mają największy baz porównaniu do innych zapisów foo z tym samym barze.