Seleccione la fila superior 1 de cada grupo

Tengo una tabla que enumera las versiones de software que están instaladas:

id | userid | version | datetime ----+--------+---------+------------------------ 111 | 75 | 10075 | 2013-03-12 13:40:58.770 112 | 75 | 10079 | 2013-03-12 13:41:01.583 113 | 78 | 10065 | 2013-03-12 14:18:24.463 114 | 78 | 10079 | 2013-03-12 14:22:20.437 115 | 78 | 10079 | 2013-03-12 14:24:01.830 116 | 78 | 10080 | 2013-03-12 14:24:06.893 117 | 74 | 10080 | 2013-03-12 15:31:42.797 118 | 75 | 10079 | 2013-03-13 07:03:56.157 119 | 75 | 10080 | 2013-03-13 07:05:23.137 120 | 65 | 10080 | 2013-03-13 07:24:33.323 121 | 68 | 10080 | 2013-03-13 08:03:24.247 122 | 71 | 10080 | 2013-03-13 08:20:16.173 123 | 78 | 10080 | 2013-03-13 08:28:25.487 124 | 56 | 10080 | 2013-03-13 08:49:44.503 

Me gustaría mostrar todos los campos de un logging de cada userid pero solo la versión más alta (también la versión es varchar ).

No especifica cómo quiere que se manejen las ataduras, pero esto lo hará si quiere que se muestren los duplicates;

 SELECT a.* FROM MyTable a LEFT JOIN MyTable b ON a.userid=b.userid AND CAST(a.version AS INT) < CAST(b.version AS INT) WHERE b.version IS NULL 

Un SQLfiddle para probar con .

Si desea eliminar los duplicates y, de existir, elija uno nuevo, deberá ampliar la consulta;

 WITH cte AS (SELECT *, CAST(version AS INT) num_version FROM MyTable) SELECT a.id, a.userid, a.version, a.datetime FROM cte a LEFT JOIN cte b ON a.userid=b.userid AND (a.num_version < b.num_version OR (a.num_version = b.num_version AND a.[datetime]<b.[datetime])) WHERE b.version IS NULL 

Otro SQLfiddle .

Si usa SQL-Server (mínimo 2005) puede usar un CTE con la function ROW_NUMBER . Puede usar CAST para la versión para get el order correcto:

 WITH cte AS (SELECT id, userid, version, datetime, Row_number() OVER ( partition BY userid ORDER BY Cast(version AS INT) DESC) rn FROM [dbo].[table]) SELECT id, userid, version, datetime FROM cte WHERE rn = 1 ORDER BY userid 

Manifestación

ROW_NUMBER devuelve siempre un logging incluso si hay varios usuarios con la misma versión (superior). Si desea devolver todos los "loggings de usuarios de la versión superior", debe replace ROW_NUMBER con DENSE_RANK .

 WITH records AS ( SELECT id, userid, version, datetime, ROW_NUMBER() OVER (PARTITION BY userID ORDER BY version DESC) rn FROM tableName ) SELECT id, userid, version, datetime FROM records WHERE RN =1 
  • Demostración de SQLFiddle
 select l.* from the_table l left outer join the_table r on l.userid = r.userid and l.version < r.version where r.version is null 

Creo que esto puede resolver su problema:

  SELECT id, userid, Version, datetime FROM ( SELECT id, userid, Version, datetime , DENSE_Rank() over (Partition BY id order by datetime asc) AS Rankk FROM [dbo].[table]) RS WHERE Rankk<2 

Usé la function de RANGO para su requerimiento …

¡El siguiente código mostrará lo que desea y es excelente para el performance!

 select * from the_table t where cast([version] as int) = (select max(cast([version] as int)) from the_table where userid = t.userid) 

Si mi experiencia de sintonía me ha enseñado algo, las generalidades son malas, malas, malas.

PERO, si la tabla de la que obtiene la Top X es grande (es decir, cientos de miles o millones). CROSS APPLY es casi universalmente el mejor. De hecho, si lo comparas, la aplicación cruzada se desempeña de manera constante y admirable a escalas más pequeñas también (en decenas de miles) y siempre cubre el requisito de potenciales con loops .

Algo como:

 select id ,userid ,version ,datetime from TheTable t cross apply ( select top 1 --with ties id from TheTable where userid = t.userid order by datetime desc )