2009-08-16 10 views
6

Les gars, j'ai une requête où, fondamentalement, sélectionnez le dernier navigateur que notre utilisateur a utilisé.Sélectionnez le haut de la jointure externe gauche

voici notre structure de la table (simplifiée)

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

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

et voici comment je questionne le dernier navigateur que notre utilisateur a utilisé

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 

Le HITS_TABLE est vient d'être ajouté il y a quelques jours. Par conséquent, cette requête ne concerne que les utilisateurs qui ont visité notre site Web après l'ajout de HITS_TABLE et l'élimination des autres.

Voici le cas de l'échantillon

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' 

Voici le résultat de l'échantillon

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

Mais, je veux ajouter d'autres utilisateurs avec le navigateur « inconnu ». Voici mon résultat souhaité

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

Je crois qu'il pourrait être atteint par LEFT OUTER JOIN. Mais j'avais toujours ceci: (Je ne veux pas que ce résultat)

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

J'espère que ma question est claire.

Répondre

6

à l'aide d'un groupe par le userid contre la hits_table vous permet d'obtenir le hitsdate max() pour chaque ID utilisateur. J'ai appelé ce dernier HITS dans le code ci-dessous.

Sélectionner USER TABLE avec une jointure à gauche pour LATEST HITS vous permet de générer des enregistrements pour chaque utilisateur. Rejoindre la table HITS vous permet ensuite de récupérer l'enregistrement du navigateur associé à cette date, ou une valeur nulle pour les utilisateurs sans enregistrement.

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

Cette solution tient compte d'un fait important, à savoir que les autres sont manquants: que se passe-t-il si la combinaison de USERID et HITSDATE est ambiguë, par ex. une ligne supplémentaire (2, 16/8/2009, 'Safari') existe? En utilisant les fonctions de classement, vous obtiendrez un résultat non-déterministe. Pouvez-vous dire lequel est sélectionné? Cette solution fournirait les deux cominations qui est à mon humble avis beaucoup mieux. –

+0

Informations supplémentaires: Pour plus d'informations sur le classement de SQL Server, voir http://msdn.microsoft.com/en-us/library/ms189798%28SQL.90%29.aspx –

+0

vous avez raison. La fonction max() est très utile pour cela. Je vous remercie. mais je pense qu'il devrait être laissé rejoindre externe. –

3

Impossible que vous sélectionnez sous, pas joli mais devrait fonctionner ..

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

Si vous souhaitez accéder à une autre colonne autre que le navigateur de la table de résultats dans cette requête, la sous-sélection n'est pas pour vous. Dans ce cas, je voudrais profiler @rwarren et @gbn solutions pour voir ce qui fonctionne mieux. @Mao a un point intéressant sur les résultats non-déterministes. Avec votre chapeau pragmatique sur vous pourriez probablement ignorer ce cas de bord en ajoutant le temps à vous 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

Dans votre solution, le sous-select ne s'exécutera-t-il pas deux fois si le résultat n'est pas nul? Tout d'abord pour évaluer le "quand" et découvrir le navigateur n'est pas nul et Deuxièmement dans le "else" pour extraire le résultat? –

Questions connexes