2010-09-12 16 views
9

Tengo dos tablas, una almacena a los usuarios, la otra almacena las direcciones de correo electrónico de los usuarios.PRIMER PEDIDO POR ... LUEGO GRUPO POR

  • tabla de usuarios: (userId, username, etc) USEREMAIL
  • tabla: (emailId, userId, email)

me gustaría hacer una consulta que me permite obtener los últimos correo electrónico dirección junto con el registro del usuario.
Estoy básicamente en busca de una consulta que dice

FIRST ORDER BY userEmail.emailId DESC 
THEN GROUP BY userEmail.userId 

Esto se puede hacer con:

SELECT 
    users.userId 
, users.username 
, (
    SELECT 
     userEmail.email 
    FROM userEmail 
    WHERE userEmail.userId = users.userId 
    ORDER BY userEmail.emailId DESC 
    LIMIT 1 
) AS email 
FROM users 
ORDER BY users.username; 

Pero esto una subconsulta para cada fila y es muy ineficiente. (Es más rápido hacer 2 consultas separadas y 'unirlas' en mi lógica de programa).


La consulta intuitiva para escribir lo que quiero sería:

SELECT 
    users.userId 
, users.username 
, userEmail.email 
FROM users 
LEFT JOIN userEmail USING(userId) 
GROUP BY users.userId 
ORDER BY 
    userEmail.emailId 
, users.username; 

Pero, esto no funciona como se quisiera. (El GROUP BY se realiza antes de la clasificación, por lo que el ORDER BY userEmail.emailId no tiene nada que ver).


Así que mi pregunta es:
¿Es posible escribir la primera consulta sin hacer uso de las subconsultas?


He buscado y leí las otras preguntas en stackoverflow, pero ninguna parece responder a la pregunta sobre este patrón de consulta.

+1

¿Puedo pedir lo que su motivación era almacenar el correo a separar? – RobertPitt

+1

¿Está utilizando el último ID de correo electrónico como una indicación de qué dirección de correo electrónico es la dirección de correo electrónico principal del usuario? Eso evitaría que los usuarios seleccionaran una dirección de correo electrónico anterior como principal. ¿Ha considerado simplemente agregar un emailId a la tabla de usuarios? – NamshubWriter

+0

cuando los usuarios cambian su dirección de correo electrónico, se agrega la nueva dirección, las direcciones de correo electrónico anteriores se mantienen durante un año antes de su eliminación (según las especificaciones) – Jacco

Respuesta

4

Pero esto lo hace una subconsulta para cada fila y es muy ineficiente

En primer lugar, ¿tiene un plan de consulta/Tiempos que demuestran esto? La forma en que lo ha hecho (con la subselección) es más o menos la manera "intuitiva" de hacerlo. Muchos DBMS (aunque no estoy seguro acerca de MySQL) tienen optimizaciones para este caso, y tendrán una forma de ejecutar la consulta solo una vez.

Alternativamente, usted debe ser capaz de crear una subtabla con sólo (user id, latest email id) tuplas y JOIN a ese:

SELECT 
    users.userId 
, users.username 
, userEmail.email 
FROM users 
INNER JOIN 
     (SELECT userId, MAX(emailId) AS latestEmailId 
     FROM userEmail GROUP BY userId) 
     AS latestEmails 
     ON (users.userId = latestEmails.userId) 
INNER JOIN userEmail ON 
     (latestEmails.latestEmailId = userEmail.emailId) 
ORDER BY users.username; 
1

Si esta es una consulta que haces a menudo, te recomiendo optimizar tus tablas para manejar esto.

Sugiero agregar una columna emailId a la tabla users. Cuando un usuario cambia su dirección de correo electrónico, o establece una dirección de correo electrónico más antiguo como la dirección de correo electrónico principal, actualizar la fila del usuario en la tabla users para indicar la corriente emailId

Una vez que modificar su código para hacer esta actualización, puede ir respalde y actualice sus datos anteriores para configurar emailId para todos los usuarios.

Como alternativa, puede agregar una columna email a la tabla users, por lo que no tiene que hacer una combinación para obtener la dirección de correo electrónico actual de un usuario.