¿Cómo se selecciona cada fila n-ésima de mysql?

79

Tengo una serie de valores en una base de datos que necesito extraer para crear un gráfico de líneas. Como no requiero alta resolución, me gustaría volver a muestrear los datos seleccionando cada quinta fila de la base de datos.

Corban Brook
fuente

Respuestas:

84
SELECT * 
FROM ( 
    SELECT 
        @row := @row +1 AS rownum, [column name] 
    FROM ( 
        SELECT @row :=0) r, [table name] 
    ) ranked 
WHERE rownum % [n] = 1 
Taylor Leese
fuente
5
¿Alguien puede proporcionar más información sobre cómo funciona esto? Por ejemplo, la pregunta se hace para cada quinta fila y no se menciona el 5 en la respuesta.
Crazometer
4
@Crazometer reemplace [n]en la consulta con 5 para obtener cada quinta fila.
Benjamin Manns
Para ampliar esto, ¿qué pasa si no desea comenzar con la primera fila sino con la segunda, por ejemplo?
HPWD
@HPWD debería reemplazar @row :=0con@row :=2
Binar Web
@BinarWeb no, cambiaría el = 1a= 2
ysth
55

Puede probar el mod 5 para obtener filas donde el ID es múltiplo de 5. (Suponiendo que tenga algún tipo de columna de ID que sea secuencial)

select * from table where table.id mod 5 = 0;
Owen
fuente
19
También asumiendo que no tiene espacios en la secuencia, debido a la eliminación o reversión.
Bill Karwin
3
Esto funcionaría en su mayor parte, pero no tiene en cuenta las filas eliminadas.
Corban Brook
2
Simple y brillante para algunas pruebas :-)
Rickard Liljeberg
1
Esto tiene sentido si su selección recupera todos los datos. Si tiene criterios adicionales en su selección, entonces sería difícil decir qué datos (si los hay) recuperaría.
j_kubik
24

Como dijiste que estás usando MySQL, puedes usar variables de usuario para crear una numeración de filas continua. Sin embargo, debe poner eso en una tabla derivada (subconsulta).

SET @x := 0;
SELECT *
FROM (SELECT (@x:=@x+1) AS x, mt.* FROM mytable mt ORDER BY RAND()) t
WHERE x MOD 5 = 0;

Agregué ORDER BY RAND()para obtener un muestreo pseudoaleatorio, en lugar de permitir que cada quinta fila de la tabla desordenada esté en la muestra cada vez.


Un usuario anónimo intentó editar esto para cambiar x MOD 5 = 0a x MOD 5 = 1. Lo he vuelto a cambiar a mi original.

Para el registro, uno puede usar cualquier valor entre 0 y 4 en esa condición, y no hay razón para preferir un valor sobre otro.

Bill Karwin
fuente
Estaba actualizando mi respuesta a esto, ¡y me ganaste! Buen pensamiento.
Josh Stodola
1
desafortunadamente, esto ralentiza la ejecución al menos x100 cuando se trabaja con muchas entradas
phil294
10
SET @a = 0;
SELECT * FROM t where (@a := @a + 1) % 2 = 0;
Andrey Kon
fuente
Esto funciona muy bien para particionar una tabla arbitraria de solo lectura para el procesamiento paralelo de las filas, y la sintaxis es muy fácil de leer y comprender. Solo necesita agregar un ORDER BY en la columna de clave principal para asegurarse de que cada fila se devuelva solo una vez.
humbads
2

Estaba buscando algo como esto. La respuesta de Taylor y Bill me llevó a mejorar sus ideas.

la tabla data1 tiene campos read_date, valor que queremos seleccionar cada registro 2d de una consulta limitada por un rango de read_date el nombre de la tabla derivada es arbitrario y aquí se llama DT

consulta:

 SET @row := 0;
  SELECT * FROM  ( SELECT @row := @row +1 AS rownum, read_date, value  FROM data1  
  WHERE  read_date>= 1279771200 AND read_date <= 1281844740 ) as DT WHERE MOD(rownum,2)=0
Mark Richards
fuente
Gracias, estaba buscando esto. Necesitaba verificar de alguna manera si una determinada columna en una tabla de registro para procedimientos almacenados tenía el mismo valor cada segunda vez. Como 'inicio de proc', 'finalización de proc'. El siguiente sql resultará en 1 si todo está bien. SET @row := 0; SELECT count(distinct Message) FROM ( SELECT @row := @row +1 AS rownum, Message FROM operations.EventLog WHERE LogTime > now() - interval 6 hour and ProcedureName = 'Do_CDR' ) as DT WHERE MOD(rownum,2)=0;
eigil
1

Puede utilizar esta consulta,

set @n=2; <!-- nth row -->
select * from (SELECT t.*, 
       @rowid := @rowid + 1 AS ID
  FROM TABLE t, 
       (SELECT @rowid := 0) dummy) A where A.ID mod @n = 0;

o puede reemplazar n con su enésimo valor

Mohideen bin Mohammed
fuente
1
SELECT *
FROM ( 
    SELECT @row := @row +1 AS rownum, posts.*
    FROM (
        SELECT @row :=0) r, posts
    ) ranked
WHERE rownum %3 = 1

donde las publicaciones es mi mesa.

Gor
fuente
1

Si está usando MariaDB 10.2, MySQL 8 o posterior, puede hacer esto de manera más eficiente, y creo que con más claridad, usando expresiones de tabla comunes y funciones de ventana .

WITH ordering AS (
  SELECT ROW_NUMBER() OVER (ORDER BY name) AS n, example.* 
    FROM example ORDER BY name
)
SELECT * FROM ordering WHERE MOD(n, 5) = 0;

Conceptualmente, esto crea una tabla temporal con el contenido de la exampletabla ordenada por el namecampo, agrega un campo adicional llamado nque es el número de fila, y luego recupera solo aquellas filas con números que son exactamente divisibles por 5, es decir, cada quinta fila. En la práctica, el motor de la base de datos a menudo puede optimizar esto mejor que eso. Pero incluso si no lo optimiza más, creo que es más claro que usar variables de usuario de forma iterativa como tenía que hacerlo en versiones anteriores de MySQL.

Richard Smith
fuente
0

Si no necesita el número de fila en el conjunto de resultados, puede simplificar la consulta.

SELECT 
    [column name] 
FROM
    (SELECT @row:=0) temp, 
    [table name] 
WHERE (@row:=@row + 1) % [n] = 1 

Reemplace los siguientes marcadores de posición:

  1. Reemplace [column name]con una lista de columnas que necesita recuperar.
  2. Reemplazar [table name] con el nombre de su tabla.
  3. Reemplazar [n]con un número. por ejemplo, si necesita cada quinta fila, reemplácela con 5
Dharman
fuente
Gracias, está cerca, pero es mejor que haga esto: seleccione el nombre de (SELECT @row: = - 1) temp, t donde (@row: = @ row + 1)% 1 = 0; Esto tiene dos ventajas. Primero, independientemente de n, siempre obtienes la primera fila y, en segundo lugar, si haces n = 1, obtienes todos los valores en lugar de ninguno. (Dos cambios: el -1 en la fila: = - 1 y n = 0 en lugar de n = 1)
Bruce