2009-08-16 3 views
6

Guys, ich habe eine Abfrage, wo grundsätzlich wählen Sie den neuesten Browser, den unser Benutzer verwendet.Wählen Sie die oberste von links äußeren Join

hier ist unsere (vereinfacht) Tabellenstruktur

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

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

und hier ist, wie ich die neueste Browser abfragen, die unsere Benutzer verwendet

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 

Die HITS_TABLE ist gerade vor einigen Tagen gegeben.

Also, diese Abfrage ist nur resultierende Benutzer, die unsere Website besucht haben, nachdem wir die HITS_TABLE hinzugefügt, und die anderen zu beseitigen. Hier

ist die Probe Fall

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' 

Hier ist das Probenergebnis

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

Aber ich andere Benutzer hinzufügen möchten mit ‚unbekannt‘ Browser. Hier ist mein gewünschtes Ergebnis

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

Ich glaube, es durch LEFT OUTER JOIN erreicht werden kann. Aber ich dies immer hatte: (Ich will nicht dieses Ergebnis)

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

Ich hoffe, meine Frage ist klar.

Antwort

6

, indem Sie auf Benutzer-ID eine Gruppe mit gegen die hits_table können Sie die max() hitsdate für jede Benutzer-ID bekommen. Ich habe diese LETZTE HITS im folgenden Code aufgerufen.

Wenn Sie in der USER TABLE mit einer linken Verknüpfung zu LATEST HITS auswählen, können Sie Datensätze für jeden Benutzer abrufen.

Wenn Sie wieder auf die HITS TABLE zugreifen, können Sie den Browserdatensatz abrufen, der diesem Datum zugeordnet ist, oder eine Null für Benutzer ohne Datensatz.

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

Diese Lösung berücksichtigt eine wichtige Tatsache, dass die anderen fehlen: Was passiert, wenn die Kombination von USERID und HITSDATE mehrdeutig ist, z. eine zusätzliche Zeile (2, 16/8/2009, 'Safari') existiert? Mit Ranking-Funktionen erhalten Sie ein nicht-deterministisches Ergebnis. Kannst du sagen, welcher ausgewählt ist? Diese Lösung würde beide Kombinationen bieten, was IMHO viel besser ist. –

+0

Zusätzliche Informationen: Weitere Informationen zum SQL Server Ranking finden Sie unter http://msdn.microsoft.com/en-us/library/ms189798%28SQL.90%29.aspx –

+0

Sie haben Recht. Die Funktion max() ist dafür sehr nützlich. Danke. aber ich denke, es sollte Outer Join bleiben. –

3

Könnten Sie nicht sub wählen, nicht schön, aber funktionieren sollte ..

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

Wenn Sie auf andere Spalte außer Browser aus der Treffer-Tabelle in dieser Abfrage zugreifen möchten, ist die Unterauswahl nicht für Sie. In diesem Fall würde ich @rwarren und @gbn Lösungen profilieren, um zu sehen, welche besser funktioniert. @Mao hat einen interessanten Punkt über nicht-deterministische Ergebnisse. Mit Ihrem pragmatischen Hut könnten Sie diesen Randfall wahrscheinlich ignorieren, indem Sie Zeit zu Ihrem HITSDATE hinzufügen. –

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

In Ihrer Lösung würde die Subauswahl nicht zweimal ausgeführt, wenn das Ergebnis nicht null ist? Erstens, um das "wann" zu bewerten und herauszufinden, der Browser ist nicht null und zweitens in der "else", um das Ergebnis zu extrahieren? –

Verwandte Themen