2010-04-08 11 views
9

Dado el siguiente ejemplo de datos:SQL Únete a sólo el rompecabezas de fila máximo

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 | 
+---------+-------------+-------------+ 

me gustaría escribir una consulta SQL que daría el siguiente resultado:

+--------------------+------------+-----------+----------------+---------------+-------------+ 
| 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 | 
+--------------------+------------+-----------+----------------+---------------+-------------+ 

Mi problema es que la fecha máxima de "Asignación activada" para cada usuario debe seleccionarse para cada usuario individual y usarse para la unión real ...

¿Hay alguna forma inteligente de lograr esto en SQL?

+2

¿Así que tienes la vieja laptop de Jon Skeet? Kewl! – APC

+1

@APC: ¡Sí! La compañía pensó que estaba pasando demasiado tiempo en StackOverflow ... :) –

Respuesta

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 diferencia entre esto y la respuesta de Justin Niessner es donde aparece la subconsulta; aquí, lo he creado en la cláusula FROM. Esto prácticamente garantiza que se ejecuta una vez. Cuando hay una subconsulta correlacionada en la cláusula WHERE como en la respuesta de Justin, es posible que el optimizador ejecute la subconsulta una vez para cada fila, que es más costosa cuando las tablas son grandes. Un optimizador muy bueno podría aplanar las cosas para que las dos sean equivalentes.

+0

+1 Si el OP puede hacer que esta versión funcione, funcionará mucho mejor que mi publicación (para grandes conjuntos de datos ... y siempre que el optimizador de consultas no aplana mi consulta para que funcione de esta manera). –

+0

@Justing Niessner: Se movió la respuesta aceptada a esta basada en el comentario anterior. Por favor, no lo tomes personalmente :) –

+0

+1 Probado esto brevemente, gran ganancia. Sin embargo, debe tenerse en cuenta que la consulta correlacionada puede tener un mejor rendimiento si la consulta externa tiene una alta selectividad y las tablas son enormes (aunque luego es fácil mejorar la consulta anterior repitiendo los criterios de selección en la consulta 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) 

Eso te puede acercar. No estoy seguro de si es exacto.

+0

+1 Me pegó :) – Unreason

+0

Ajuste las columnas según sus necesidades, pero la parte clave de la solución es la sub consulta. –

+0

¡Doh! * Bill se siente un poco tonto ahora –

0

Utilice group by y max para filtrar los resultados de la unión.

+0

Eso solo devuelve una fila. Necesito una fila por usuario. –

Cuestiones relacionadas