¿Hay una buena manera en MySQL para replicar la función de SQL Server ROW_NUMBER()
?
Por ejemplo:
SELECT
col1, col2,
ROW_NUMBER() OVER (PARTITION BY col1, col2 ORDER BY col3 DESC) AS intRow
FROM Table1
Entonces podría, por ejemplo, agregar una condición para limitar intRow
a 1 para obtener una sola fila con la más alta col3
para cada (col1, col2)
par.
greatest-n-per-group
para guiarlo a preguntas similares.Sql-Server
etiqueta, ya que este fue el elemento más votado en la búsqueda combinada de etiquetas, pero no es realmente relevante para SQL Server.Respuestas:
Es un máximo grupal , una de las preguntas SQL más frecuentes (ya que parece que debería ser fácil, pero en realidad no lo es).
A menudo me vuelvo loco por una unión nula:
"Obtenga las filas en la tabla para las cuales ninguna otra fila con col1 coincidente, col2 tiene una col3 más alta". (Notará que esta y la mayoría de las otras soluciones grupales máximas devolverán varias filas si más de una fila tiene el mismo col1, col2, col3. Si ese es un problema, es posible que necesite algo de procesamiento posterior).
fuente
SELECT t1.id FROM test t1 LEFT JOIN test t2 ON t1.id>t2.id WHERE t2.id IS NULL;
¿No requieren*n/2 + n/2
comparaciones IS NULL para encontrar la fila única? ¿Hay alguna optimización que no veo? Traté de hacerle una pregunta similar a Bill en otro hilo, pero parece haberlo ignorado.SELECT t0.col3 FROM table AS t0 WHERE NOT EXISTS (select 1 from table AS t1 ON t0.col1=t1.col1 AND t0.col2=t1.col2 AND t1.col3>t0.col3)
No hay funcionalidad de clasificación en MySQL. Lo más cercano que puede obtener es usar una variable:
Si. Si se tratara de Oracle, podría usar la función LEAD para alcanzar el pico en el siguiente valor. Afortunadamente, Quassnoi cubre la lógica de lo que necesita implementar en MySQL .
fuente
SELECT @row_num:=@row_num+1 AS row_number, t.id FROM (SELECT * FROM table1 WHERE col = 264 ORDER BY id) t, (SELECT @row_num:=0) var;
Siempre termino siguiendo este patrón. Dada esta tabla:
Puedes obtener este resultado:
Al ejecutar esta consulta, que no necesita ninguna variable definida:
¡Espero que ayude!
fuente
<
,>
,<=
,>=
CHAR mango y tipos de datos VARCHAR en orden alfabético; Espero, es exactamente lo que estás buscando.row_numbers <= 2
y muchas gracias por esta respuesta Mosty, ¡es perfecto!fuente
Consulte este artículo, muestra cómo imitar SQL ROW_NUMBER () con una partición en MySQL. Me encontré con este mismo escenario en una implementación de WordPress. Necesitaba ROW_NUMBER () y no estaba allí.
http://www.explodybits.com/2011/11/mysql-row-number/
El ejemplo en el artículo está usando una sola partición por campo. Para particionar por campos adicionales, puede hacer algo como esto:
El uso de concat_ws maneja los valores nulos. Probé esto en 3 campos usando int, date y varchar. Espero que esto ayude. Consulte el artículo, ya que desglosa esta consulta y la explica.
fuente
limit 18446744073709551615
a laorder by
cláusula force .concat_ws
con la cadena vacía''
es peligroso:concat_ws('',12,3) = concat_ws('',1,23)
. Es mejor usar un separador'_'
o usar la solución @Kenneth Xu.Desde
MySQL 8.0.0
y arriba, puede usar de forma nativa funciones con ventana.1.4 Qué hay de nuevo en MySQL 8.0 :
ROW_NUMBER () over_clause :
Manifestación:
DBFiddle Demo
fuente
También votaría por la solución de Mosty Mostacho con modificaciones menores en su código de consulta:
Lo que dará el mismo resultado:
para la mesa:
Con la única diferencia de que la consulta no usa JOIN y GROUP BY, se basa en select anidado en su lugar.
fuente
Yo definiría una función:
entonces podría hacer:
Ahora no tiene una subconsulta, que no puede tener en las vistas.
fuente
consulta por row_number en mysql
fuente
No existe una función como
rownum
,row_num()
en MySQL, pero la forma de evitarlo es la siguiente:fuente
La solución que mejor funcionó fue usar una subconsulta como esta:
Las columnas PARTITION BY simplemente se comparan con '=' y se separan con AND. Las columnas ORDER BY se compararían con '<' o '>' y se separarían por OR.
He encontrado que esto es muy flexible, incluso si es un poco costoso.
fuente
La funcionalidad de rownumber no se puede imitar. Es posible que obtenga los resultados que espera, pero lo más probable es que se decepcione en algún momento. Esto es lo que dice la documentación de mysql:
Saludos, Georgi.
fuente
MariaDB 10.2 está implementando "Funciones de ventana", incluyendo RANK (), ROW_NUMBER () y varias otras cosas:
https://mariadb.com/kb/en/mariadb/window-functions/
Según una charla en Percona Live este mes, están razonablemente bien optimizados.
La sintaxis es idéntica al código en la pregunta.
fuente
No veo ninguna respuesta simple que cubra la parte "PARTICIÓN POR", así que aquí está la mía:
En este ejemplo simple, solo pongo uno pero puedes tener varias partes "PARTITION BY"
fuente
Un poco tarde pero también puede ayudar a alguien que busca respuestas ...
Ejemplo entre filas / número de fila: consulta recursiva que se puede usar en cualquier SQL:
fuente
Esto permite lograr la misma funcionalidad que ROW_NUMBER () Y PARTITION BY en MySQL
fuente
También un poco tarde, pero hoy tenía la misma necesidad, así que busqué en Google y finalmente encontré un enfoque general simple aquí en el artículo de Pinal Dave http://blog.sqlauthority.com/2014/03/09/mysql-reset-row -número-para-cada-grupo-partición-por-fila-número /
Quería centrarme en la pregunta original de Paul (ese también era mi problema), así que resumo mi solución como un ejemplo de trabajo.
Debido a que queremos particionar en dos columnas, crearía una variable SET durante la iteración para identificar si se inició un nuevo grupo.
El 3 significa en el primer parámetro de MAKE_SET que quiero ambos valores en el SET (3 = 1 | 2). Por supuesto, si no tenemos dos o más columnas para construir los grupos, podemos eliminar la operación MAKE_SET. La construcción es exactamente la misma. Esto está funcionando para mí según sea necesario. Muchas gracias al Pinal Dave por su clara demostración.
fuente
ORDER BY
en cuenta que en una subconsulta podría ignorarse (consulte mariadb.com/kb/en/mariadb/… ). La solución sugerida para eso es agregarLIMIT 18446744073709551615
a la subconsulta, lo que obliga a una especie. Sin embargo, esto podría causar problemas de rendimiento y no es válido para tablas realmente enormes :)Esto también podría ser una solución:
fuente
MySQL ha admitido ROW_NUMBER () desde la versión 8.0+ .
Si usa MySQL 8.0 o posterior, échele un vistazo a la función ROW_NUMBER (). De lo contrario, debe emular la función ROW_NUMBER ().
Row_number () es una función de clasificación que devuelve un número secuencial de una fila, comenzando desde 1 para la primera fila.
para la versión anterior,
fuente
Importante: considere actualizar a MySQL 8+ y use la función definida y documentada ROW_NUMBER (), y elimine los viejos hacks vinculados a una versión antigua limitada de características de MySQL
Ahora aquí está uno de esos hacks:
Las respuestas aquí que usan variables de consulta en su mayoría / todas parecen ignorar el hecho de que la documentación dice (parafraseando):
Como tal, existe el riesgo de que generen la respuesta incorrecta, porque generalmente hacen un
Si alguna vez se evalúan de abajo hacia arriba, el número de fila dejará de funcionar (sin particiones)
Por lo tanto, debemos usar algo con un orden de ejecución garantizado. Ingrese CASO CUANDO:
Como se describe en ld, el orden de asignación de prevcol es importante: se debe comparar prevcol con el valor de la fila actual antes de asignarle un valor de la fila actual (de lo contrario, sería el valor col de las filas actuales, no el valor col de la fila anterior) .
Así es como encaja esto:
El primero CUANDO se evalúa. Si la columna de esta fila es igual a la columna de la fila anterior, entonces @r se incrementa y se devuelve desde CASE. Estos valores de retorno de led se almacenan en @r. Es una característica de MySQL que la asignación devuelve el nuevo valor de lo que se asigna a @r en las filas de resultados.
Para la primera fila del conjunto de resultados, @prevcol es nulo (se inicializa como nulo en la subconsulta), por lo que este predicado es falso. Este primer predicado también devuelve falso cada vez que cambia la columna (la fila actual es diferente a la fila anterior). Esto hace que el segundo CUANDO sea evaluado.
El segundo predicado WHEN siempre es falso, y existe únicamente para asignar un nuevo valor a @prevcol. Debido a que la columna de esta fila es diferente de la columna de la fila anterior (sabemos esto porque si fuera lo mismo, el primer CUANDO se hubiera utilizado), tenemos que asignar el nuevo valor para mantenerlo para probar la próxima vez. Debido a que la asignación se realiza y luego el resultado de la asignación se compara con nulo, y todo lo que se equipare con nulo es falso, este predicado siempre es falso. Pero al menos evaluarlo hizo su trabajo al mantener el valor de col de esta fila, por lo que puede evaluarse contra el valor de col de la siguiente fila
Debido a que el segundo CUANDO es falso, significa que en situaciones donde la columna por la que estamos particionando (col) ha cambiado, es ELSE el que da un nuevo valor para @r, reiniciando la numeración desde 1
Llegamos a una situación en la que esto:
Tiene la forma general:
Notas al pie:
La p en pcol significa "partición", la o en ocol significa "orden" - en la forma general eliminé la "anterior" del nombre de la variable para reducir el desorden visual
Los corchetes
(@pcolX := colX) = null
son importantes. Sin ellos asignarás nulo a @pcolX y las cosas dejarán de funcionarEs un compromiso que el conjunto de resultados también debe ser ordenado por las columnas de partición, para que la columna anterior se pueda comparar. Por lo tanto, no puede ordenar su número de rown de acuerdo con una columna, pero su conjunto de resultados se ordenó a otro. Es posible que pueda resolver esto con subconsultas, pero creo que los documentos también indican que el pedido de subconsultas puede ignorarse a menos que se use LIMIT y esto podría afectar actuación
No he profundizado en ello más allá de probar que el método funciona, pero si existe el riesgo de que los predicados en el segundo CUANDO se optimicen (cualquier cosa en comparación con nulo es nulo / falso, ¿por qué molestarse en ejecutar la asignación?) Y no se ejecuta , también se detiene. Esto no parece suceder en mi experiencia, pero con mucho gusto aceptaré comentarios y propondré una solución si pudiera ocurrir razonablemente.
Puede ser conveniente convertir los valores nulos que crean @pcolX a los tipos reales de sus columnas, en la subconsulta que crea las variables @pcolX, a saber:
select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
fuente
Esta no es la solución más sólida, pero si solo está buscando crear un rango particionado en un campo con solo unos pocos valores diferentes, puede que no sea difícil usar algún caso cuando la lógica con tantas variables como necesite.
Algo como esto me ha funcionado en el pasado:
Espero que tenga sentido / ayuda!
fuente
Esto funciona perfectamente para mí para crear RowNumber cuando tenemos más de una columna. En este caso dos columnas.
fuente
fuente
fuente