2009-06-18 33 views
6

Lo que tengo es básicamente un problema que se resuelve fácilmente con varias tablas, pero solo tengo una tabla para hacerlo.SQL - SELECCIONAR MAX() y el campo correspondiente

Tenga en cuenta la siguiente tabla de base de datos

UserID UserName EmailAddress   Source 
3K3S9 Ben  [email protected]  user 
SF13F Harry [email protected] 3rd_party 
SF13F Harry [email protected] user 
76DSA Lisa  [email protected]  user 
OL39F Nick  [email protected] 3rd_party 
8F66S Stan  [email protected]  user 

necesito para seleccionar todos los campos, pero sólo que cada usuario una vez junto con uno de sus direcciones de correo electrónico (el "mayor" uno según lo determinado por el MAX (función)) Este es el resultado que busco ...

UserID UserName EmailAddress   Source 
3K3S9 Ben  [email protected]  user 
SF13F Harry [email protected] 3rd_party 
76DSA Lisa  [email protected]  user 
OL39F Nick  [email protected] 3rd_party 
8F66S Stan  [email protected]  user 

Como se puede ver, "Harry" sólo se muestra una vez con su dirección de correo electrónico "más alto" del correcponding "fuente"

Actualmente lo que está sucediendo es que estamos agrupados en UserID, UserName y usando MAX() para EmailAddress y Source, pero el máximo de esos dos campos no siempre coinciden, deben ser del mismo registro.

He intentado con otro proceso uniéndome a la tabla, pero solo he logrado obtener la dirección de correo electrónico correcta pero no la "fuente" correspondiente para esa dirección.

Cualquier ayuda sería muy apreciada como he pasado demasiado tiempo tratando de resolver esto ya :)

+0

¿Tiene una columna adicional con una clave principal definida? ¿El par (UserId, EmailAddress) es único? –

Respuesta

7

Si estás en SQL Server 2005 o superior,

SELECT UserID, UserName, EmailAddress, Source 
FROM (SELECT UserID, UserName, EmailAddress, Source, 
       ROW_NUMBER() OVER (PARTITION BY UserID 
            ORDER BY EmailAddress DESC) 
        AS RowNumber 
     FROM MyTable) AS a 
WHERE a.RowNumber = 1 

Por supuesto hay formas de hacer la misma tarea sin las funciones de clasificación (SQL-Standard) como ROW_NUMBER, que SQL Server implementó solo desde 2005, incluidas las consultas dependientes anidadas y las combinaciones con un ON incluyendo un '>' y unTruco- pero las funciones de clasificación hacen que el código sea legible y (en teoría) bien optimizable por el motor de SQL Server.

Editar: this article es un buen tutorial en el ranking, pero utiliza RANK en los ejemplos en lugar de ROW_NUMBER (o la otra función de clasificación, DENSE_RANK) - la distinción es importante cuando hay "lazos" entre filas agrupadas en el mismo partición de acuerdo con los criterios de ordenamiento. this post hace un buen trabajo explicando la diferencia.

+0

Alex muy interesante, voy a estudiar sobre estas características. – tekBlues

+0

Esto ciertamente funciona muy bien ... aún no entiendo la sintaxis>. Nippysaurus

+0

Edité mi respuesta para agregar URL a dos buenos y breves tutoriales sobre funciones de clasificación - ¡HTH! –

5
select distinct * from table t1 
where EmailAddress = 
(select max(EmailAddress) from table t2 
where t1.userId = t2.userId) 
+0

Vale la pena señalar que esto a menudo puede funcionar más rápido que la respuesta aceptada, especialmente si hay un índice en {userid, EmailAddress DESC} en t2 –

0
select distinct 
    * 
from  
    SomeTable a 
inner join (
    select max(emailAddress), userId 
    from 
    SomeTable 
    group by 
    userId 
) b on a.emailAddress = b.emailAddress and a.userId = b.userId 
+0

Estaría más feliz si la condición de encendido incluye a.userID = b.userID así como también la dirección de correo electrónico. –

+0

Cierto, lo hace más específico y evita posibles problemas. He editado mi respuesta para reflejar esto. –

0

creo que tengo una solución que es diferente a los ya propuestos:

 
select * 
from foo 
where id = (
    select id 
    from foo F 
    where F.bar = foo.bar 
    order by F.baz 
    limit 1 
) 

Esto le da todos los registros foo que tienen el mayor Baz en comparación con otros registros foo con el mismo bar.

Cuestiones relacionadas