2010-04-08 8 views
9

Dato il seguente esempio di dati:SQL Iscriviti per solo il massimo di puzzle fila

Users 
+--------------------------------------------------+ 
| ID | First Name | Last Name | Network Identifier | 
+--------------------------------------------------+ 
| 1 | Billy  | O'Neal | bro4    | 
+----+------------+-----------+--------------------+ 
| 2 | John  | Skeet  | jsk1    | 
+----+------------+-----------+--------------------+ 

Hardware 
+----+-------------------+---------------+ 
| ID | Hardware Name  | Serial Number | 
+----------------------------------------+ 
| 1 | Latitude E6500 | 5555555  | 
+----+-------------------+---------------+ 
| 2 | Latitude E6200 | 2222222  | 
+----+-------------------+---------------+ 

HardwareAssignments 
+---------+-------------+-------------+ 
| User ID | Hardware ID | Assigned On | 
+-------------------------------------+ 
| 1  | 1   | April 1  | 
+---------+-------------+-------------+ 
| 1  | 2   | April 10 | 
+---------+-------------+-------------+ 
| 2  | 2   | April 1  | 
+---------+-------------+-------------+ 
| 2  | 1   | April 11 | 
+---------+-------------+-------------+ 

Mi piacerebbe scrivere una query SQL che darebbe il seguente risultato:

+--------------------+------------+-----------+----------------+---------------+-------------+ 
| Network Identifier | First Name | Last Name | Hardware Name | Serial Number | Assigned On | 
+--------------------------------------------------------------------------------------------+ 
| bro4    | Billy  | O'Neal | Latitude E6200 | 2222222  | April 10 | 
+--------------------+------------+-----------+----------------+---------------+-------------+ 
| jsk1    | John  | Skeet  | Latitude E6500 | 5555555  | April 11 | 
+--------------------+------------+-----------+----------------+---------------+-------------+ 

Il mio problema è che la data massima "Assigned On" per ciascun utente deve essere selezionata per ogni singolo utente e utilizzata per l'effettivo join ...

Esiste un modo intelligente per ottenere questo risultato in SQL?

+2

Quindi hai il vecchio laptop di Jon Skeet? Kewl! – APC

+1

@APC: Sì! La società pensava che spendesse troppo tempo su StackOverflow ... :) –

risposta

9
SELECT U.NetworkIdentifier, U.FirstName, U.LastName, 
     H.HardwareName, H.SerialNumber 
    FROM (SELECT UserID, MAX(AssignedOn) LastAssignment 
      FROM HardwareAssignments 
     GROUP BY UserID) AS T 
    JOIN HardwareAssignments AS HA 
     ON HA.UserId = T.UserID AND HA.AssignedOn = T.LastAssignment 
    JOIN Users AS U ON U.ID = HA.UserID 
    JOIN Hardware AS H ON H.ID = HA.HardwareID 
ORDER BY U.NetworkIdentifier; 

La differenza tra questa e la risposta di Justin Niessner è dove viene visualizzata la sottoquestione; qui, l'ho creato nella clausola FROM. Questo praticamente garantisce che venga eseguito una sola volta. Quando c'è una sotto-query correlata nella clausola WHERE come nella risposta di Justin, è possibile che l'ottimizzatore esegua la sotto-query una volta per ogni riga, che è più costosa quando le tabelle sono grandi. Un ottimo ottimizzatore potrebbe appiattire le cose in modo che i due siano equivalenti.

+0

+1 Se l'OP è in grado di far funzionare questa versione, funzionerà molto meglio del mio post (per insiemi di dati di grandi dimensioni ... e purché Query Optimizer non appiattisca la mia query affinché funzioni in questo modo). –

+0

@Justing Niessner: spostata la risposta accettata a questa in base al commento sopra. Si prega di non prenderlo personalmente :) –

+0

+1 Testato questo brevemente, enorme guadagno. Tuttavia, va notato che la query correlata potrebbe funzionare meglio se la query esterna ha un'elevata selettività e le tabelle sono enormi (sebbene sia quindi semplice migliorare la query sopra ripetendo i criteri di selezione nella query interna). – Unreason

8
select * from Users as u 
inner join HardwareAssignments as ha 
    on u.id = ha.userid 
inner join Hardware as h 
    on uh.hardwareid = h.id 
where ha.AssignedOn = (select max(assignedon) 
         from HardwareAssignments as ha2 
         where ha.userid = ha2.userid) 

Questo potrebbe farti chiudere. Non sono sicuro se è esatto.

+0

+1 Mi picchiato :) – Unreason

+0

Regola le colonne in base alle tue esigenze, ma la parte chiave della soluzione è la query secondaria. –

+0

Doh! * Bill si sente un po 'stupido ora –

0

Utilizzare il gruppo per e il massimo per filtrare i risultati del join.

+0

Questo restituisce solo una riga. Ho bisogno di una riga per utente. –

Problemi correlati