2009-08-16 10 views
6

Ragazzi, ho una query in cui selezionare fondamentalmente l'ultimo browser utilizzato dal nostro utente.Selezionare quello in alto dall'uniforme esterno sinistro

qui è la nostra struttura (semplificato) tavolo

HITS_TABLE 
---------- 
USERID 
BROWSER 
HITSDATE 

USER_TABLE 
---------- 
USERID 
USERNAME 

e ecco come lo interrogo l'ultima versione del browser che il nostro utente ha utilizzato

SELECT U.*, H.BROWSER 

FROM USER_TABLE U 

CROSS APPLY 
    (SELECT TOP 1 BROWSER 
    FROM HITS_TABLE 
    WHERE HITS_TABLE.USERID = U.USERID 
    ORDER BY HITS_TABLE.HITSDATE DESC 
)as H 

Il HITS_TABLE è appena aggiunto alcuni giorni fa.

Quindi, questa query è solo gli utenti che hanno avuto esito positivo visitando il nostro sito Web dopo aver aggiunto HITS_TABLE ed eliminato gli altri.

Qui è il caso del campione

USER_TABLE 
------------------- 
USERID  USERNAME 
------------------- 
1   'Spolski' 
2   'Atwoord 
3   'Dixon' 


HITS_TABLE 
------------------------------ 
USERID  HITSDATE  BROWSER 
------------------------------ 
2   15/8/2009 'Firefox 3.5' 
1   16/8/2009 'IE 6' 
2   16/8/2009 'Chrome' 

Ecco il risultato del campione

------------------------------ 
USERID  USERNAME  BROWSER 
------------------------------ 
1   'Spolsky' 'IE 6' 
2   'Atwoord' 'Chrome' 

Ma, voglio aggiungere altri utenti con il browser 'sconosciuto'. Ecco il mio risultato desiderato

------------------------------ 
USERID  USERNAME  BROWSER 
------------------------------ 
1   'Spolsky' 'IE 6' 
2   'Atwoord' 'Chrome' 
3   'Dixon'  'Unknown' 

Ritengo che possa essere raggiunto con LEFT OUTER JOIN. Ma ho sempre avuto questa: (non voglio che questo risultato)

------------------------------ 
USERID  USERNAME  BROWSER 
------------------------------ 
1   'Spolsky' 'IE 6' 
2   'Atwoord' 'Chrome' 
2   'Atwoord' 'Firefox 3.5' 
3   'Dixon'  'Unknown' 

Spero che la mia domanda è chiara.

risposta

6

utilizzando un gruppo da l'userid contro il hits_table consente di ottenere il massimo hitsdate() per ogni userid. Ho chiamato questo ULTIME battute nel codice qui sotto.

Selezionare nella TABELLA UTENTE con un join sinistro su ULTIME battute consente di estrarre i record per ogni utente.

unendosi nuovamente alla tabella HITS, quindi è tutto necessario per tirare il record del browser associato a tale data, o un null per gli utenti senza record in là.

select 
    user_table.userid, 
    user_table.username, 
    isnull(hitstable.browser, 'unknown') as browser 
from 
    user_table 
left join 
(
    select 
    userid, 
    max(hitsdate) hitsdate 
    from 
    hits_table 
    group by 
    userid 
) latest_hits 
on 
    user_table.userid = latest_hits.userid  
left join 
    hits_table 
on hits.table.userid = latest_hits.userid 
and hits_table.hitsdate = latest_hits.hitsdate 
+2

Questa soluzione tiene conto di un fatto importante, che mancano gli altri: cosa succede se la combinazione di USERID e HITSDATE è ambigua, ad es. esiste una riga aggiuntiva (2, 16/8/2009, 'Safari')? Usando le funzioni di classifica otterresti un risultato non deterministico. Puoi dire quale è selezionato? Questa soluzione fornirebbe entrambe le iniziazioni che è IMHO molto meglio. –

+0

Ulteriori informazioni: per informazioni su SQL Server Ranking vedere http://msdn.microsoft.com/en-us/library/ms189798%28SQL.90%29.aspx –

+0

hai ragione. la funzione max() è molto utile per questo. grazie. ma penso che dovrebbe essere lasciato esterno join. –

3

Potrebbe non sub select, non bella, ma dovrebbe funzionare ..

SELECT U.*, 

ISNULL((SELECT TOP 1 BROWSER 
    FROM HITS_TABLE 
    WHERE HITS_TABLE.USERID = U.USERID 
    ORDER BY HITS_TABLE.HITSDATE DESC),'UnKnown') AS Browser 

FROM USER_TABLE U 
+1

Se si desidera accedere a qualsiasi altra colonna oltre al browser dalla tabella degli hit in questa query, la selezione secondaria non fa per voi. In tal caso, vorrei profilare le soluzioni @rwarren e @gbn per vedere quale funziona meglio. @Mao ha un punto interessante sui risultati non deterministici. Con il tuo cappello pragmatico potresti probabilmente ignorare questo caso limite aggiungendo Time a te HITSDATE. –

0
SELECT U.*,'BROWSER' = 
    case 
    when (SELECT TOP 1 BROWSER FROM HITS_TABLE WHERE HITS_TABLE.USERID = U.USERID ORDER BY HITS_TABLE.HITSDATE DESC) is null then 'Unknown' 
else (SELECT TOP 1 BROWSER FROM HITS_TABLE WHERE HITS_TABLE.USERID = U.USERID ORDER BY HITS_TABLE.HITSDATE DESC) 
    end 
FROM USER_TABLE U 
+0

Nella tua soluzione, la selezione secondaria non viene eseguita due volte quando il risultato non è nullo? In primo luogo per valutare il "quando" e scoprire il browser non è nullo e in secondo luogo nel "else" per estrarre il risultato? –

Problemi correlati