你如何从MySQL中选择每第n行


79

我在数据库中有一系列值需要提取以创建折线图。因为我不需要高分辨率,所以我想通过从数据库中选择第5行来对数据进行重新采样。

Answers:


82
SELECT * 
FROM ( 
    SELECT 
        @row := @row +1 AS rownum, [column name] 
    FROM ( 
        SELECT @row :=0) r, [table name] 
    ) ranked 
WHERE rownum % [n] = 1 

5
有人可以提供有关其工作原理的更多信息吗?例如,问题每隔第5行问一次,答案中没有提及5。
Crazometer

4
@Crazometer[n]在查询中替换为5,以获取第5行。
本杰明·曼斯

为了对此进行扩展,例如,如果您不想从第一行开始而是第二行呢?
HPWD

@HPWD,您将替换@row :=0@row :=2
Binar Web

@BinarWeb不,您将更= 1改为= 2
ysth

55

您可以尝试使用mod 5获得ID为5的倍数的行(假设您具有某种顺序的ID列)。

select * from table where table.id mod 5 = 0;

19
还要假设由于删除或回滚,序列中没有间隔。
比尔·卡温

3
这将在大多数情况下有效,但不能解决已删除的行。
Corban Brook

2
简单而出色的测试:-)
Rickard Liljeberg 2014年

1
如果您的选择检索了所有数据,这将很有意义。如果您选择了其他条件,那么很难说出它将检索什么数据(如果有)。
j_kubik 2015年

24

由于您说的是使用MySQL,因此可以使用用户变量来创建连续的行编号。但是,您必须将其放入派生表(子查询)中。

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

我添加ORDER BY RAND()了一个伪随机采样,而不是每次都允许无序表的第五行出现在采样中。


匿名用户尝试对其进行编辑以更改x MOD 5 = 0x MOD 5 = 1。我已将其改回原来的状态。

出于记录目的,在那种情况下,可以使用0到4之间的任何值,并且没有理由更喜欢一个值。


我正在更新对此的答案,而您击败了我!好想法。
乔什·斯托多拉

1
不幸的是,这在处理许多条目时将执行速度至少降低了x100
phil294

10
SET @a = 0;
SELECT * FROM t where (@a := @a + 1) % 2 = 0;

这对于将任意的只读表进行分区以进行行的并行处理非常有用,并且语法非常易于阅读和理解。您只需要在主键列上添加ORDER BY,以确保每行仅返回一次。
humbads

2

我一直在寻找这样的东西。泰勒和比尔的回答使我改进了他们的想法。

table data1的字段为read_date,我们要从一个受read_date范围限制的查询中选择每2d记录的值,派生表的名称是任意的,这里称为DT

查询:

 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

谢谢,我一直在寻找这个。我需要以某种方式检查存储过程的日志表中的某列是否第二次具有相同的值。就像“过程开始”,“过程结束”一样。如果一切正常,下面的sql将返回1。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 2012年


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

我的桌子在哪里。


1

如果您使用的是MariaDB 10.2,MySQL 8或更高版本,则可以使用通用的表表达式窗口函数来提高效率,并且我认为更清楚。

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;

从概念上讲,这将创建一个临时表,该表具有examplename字段排序的表内容,添加一个名为n行号的附加字段,然后仅获取数字可被5整除的行,即每5行一次。实际上,数据库引擎通常能够对此进行更好的优化。但是,即使它没有进一步优化它,我认为它比迭代使用用户变量更清晰,就像在早期版本的MySQL中一样。


0

如果您在结果集中不需要行号,则可以简化查询。

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

替换以下占位符:

  1. 更换 [column name]您需要提取的列列表。
  2. [table name]表名替换。
  3. [n]数字代替。例如,如果您需要第5行,则将其替换为5

谢谢,它接近了,但是您最好这样做:从(SELECT @row:=-1)temp,中选择名称,其中(@row:= @ row + 1)%1 = 0; 这有两个优点。首先,无论n为何,总是得到第一行,第二行,如果n = 1,则得到所有值而不是没有值。(两个更改:行中的-1:=-1和n = 0而不是n = 1)
布鲁斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.