在MySQL中生成一个整数序列

时间:2008-11-20 06:04:54

标签: mysql

我需要使用表/结果集/具有整数n到m的任何内容进行连接。如果不构建表格,是否有一种简单的方法可以实现这一目标?

(BTW这种类型的构造会被称为“元查询”?)

m-n受限于某种合理的(< 1000's)

17 个答案:

答案 0 :(得分:94)

我在网上找到了这个解决方案

SELECT @row := @row + 1 as row, t.*
FROM some_table t, (SELECT @row := 0) r

单个查询,快速,并且完全符合我的要求:现在我可以“编号”从复杂查询中找到的“选择”,其中唯一数字从1开始,并为结果中的每一行递增一次。

我认为这也适用于上面列出的问题:调整@row的初始起始值并添加限制子句以设置最大值。

顺便说一句:我认为“r”并不是真正需要的。

DDSP

答案 1 :(得分:31)

以下将返回1..10000并且不是那么慢

SELECT @row := @row + 1 AS row FROM 
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t,
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2, 
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3, 
(select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
(SELECT @row:=0) numbers;

答案 2 :(得分:16)

如果您正好使用MariaDB fork of MySQLthe SEQUENCE engine允许直接生成数字序列。它通过使用虚拟(假)一列表来实现。

例如,要生成从1到1000的整数序列,请执行此操作

     SELECT seq FROM seq_1_to_1000;

对于0到11,请执行此操作。

     SELECT seq FROM seq_0_to_11;

从今天开始,为期一周的DATE值,请执行此操作。

SELECT FROM_DAYS(seq + TO_DAYS(CURDATE)) dateseq FROM seq_0_to_6

以“2010-01-01”开头的十年值连续DATE值执行此操作。

SELECT FROM_DAYS(seq + TO_DAYS('2010-01-01')) dateseq
  FROM seq_0_to_3800
 WHERE FROM_DAYS(seq + TO_DAYS('2010-01-01')) < '2010-01-01' + INTERVAL 10 YEAR

如果您没有使用MariaDB,请考虑它。

答案 3 :(得分:6)

MySQL中没有序列号生成器(CREATE SEQUENCE)。最近的是AUTO_INCREMENT,它可以帮助你构建表格。

答案 4 :(得分:5)

您可以尝试这样的事情:

SELECT @rn:=@rn+1 as n
FROM (select @rn:=2)t, `order` rows_1, `order` rows_2 --, rows_n as needed...
LIMIT 4

其中order只是一些具有相当大的行集的表的示例。

编辑:原来的答案是错误的,任何功劳应归功于David Poor,他提供了相同概念的实例

答案 5 :(得分:3)

1到100.000之间的数字序列:

SELECT e*10000+d*1000+c*100+b*10+a n FROM
(select 0 a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1,
(select 0 b union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2,
(select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3,
(select 0 d union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4,
(select 0 e union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t5
order by 1

我用它来审核一些数字是否不按顺序排列,如下所示:

select * from (
    select 121 id
    union all select 123
    union all select 125
    union all select 126
    union all select 127
    union all select 128
    union all select 129
) a
right join (
    SELECT e*10000+d*1000+c*100+b*10+a n FROM
    (select 0 a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t1,
    (select 0 b union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t2,
    (select 0 c union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t3,
    (select 0 d union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t4,
    (select 0 e union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) t5
    order by 1
) seq on seq.n=a.id
where seq.n between 121 and 129
and   id is null

结果将是121和129之间序列的122和124的间隙:

id     n
----   ---
null   122
null   124

也许对某人有帮助!

答案 6 :(得分:3)

有一种方法可以在一个查询中获取一系列值,但它有点慢。它可以通过使用缓存表来加速。

假设您想要一个具有所有BOOLEAN值范围的选择:

SELECT 0 as b UNION SELECT 1 as b;

我们可以发表观点

CREATE VIEW ViewBoolean AS SELECT 0 as b UNION SELECT 1 as b;

然后你可以通过

做一个字节
CREATE VIEW ViewByteValues AS
SELECT b0.b + b1.b*2 + b2.b*4 + b3.b*8 + b4.b*16 + b5.b*32 + b6.b*64 + b7.b*128 as v FROM
ViewBoolean b0,ViewBoolean b1,ViewBoolean b2,ViewBoolean b3,ViewBoolean b4,ViewBoolean b5,ViewBoolean b6,ViewBoolean b7;

然后你可以做一个

CREATE VIEW ViewInt16 AS
SELECT b0.v + b1.v*256 as v FROM
ViewByteValues b0,ViewByteValues b1;

然后你可以做一个

SELECT v+MIN as x FROM ViewInt16 WHERE v<MAX-MIN;

为了加快速度,我跳过了字节值的自动计算,并使自己成为了

CREATE VIEW ViewByteValues AS
SELECT 0 as v UNION SELECT 1 as v UNION SELECT ...
...
...254 as v UNION SELECT 255 as v;

如果您需要一系列日期,您可以这样做。

SELECT DATE_ADD('start_date',v) as day FROM ViewInt16 WHERE v<NumDays;

SELECT DATE_ADD('start_date',v) as day FROM ViewInt16 WHERE day<'end_date';

您可以使用稍快的MAKEDATE功能

加快速度
SELECT MAKEDATE(start_year,1+v) as day FRON ViewInt16 WHERE day>'start_date' AND day<'end_date';

请注意,这个技巧非常慢,只允许在预定义的域中创建FINITE序列(例如int16 = 0 ... 65536)

我相信你可以通过暗示MySQL停止计算来改进查询以加快速度;)(使用ON子句而不是WHERE子句和类似的东西)

例如:

SELECT MIN + (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) FROM
ViewByteValues b0,
ViewByteValues b1,
ViewByteValues b2,
ViewByteValues b3
WHERE (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) < MAX-MIN;

将使您的SQL服务器忙碌几个小时

然而

SELECT MIN + (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) FROM
ViewByteValues b0
INNER JOIN ViewByteValues b1 ON (b1.v*256<(MAX-MIN))
INNER JOIN ViewByteValues b2 ON (b2.v*65536<(MAX-MIN))
INNER JOIN ViewByteValues b3 ON (b3.v*16777216<(MAX-MIN)
WHERE (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) < (MAX-MIN);

运行速度相当快 - 即使MAX-MIN很大,只要你用LIMIT 1,30或其他东西限制结果。然而,一个COUNT(*)将需要很长时间,如果你在MAX-MIN大于100k时错误地添加ORDER BY,那么再次计算将需要几秒钟......

答案 7 :(得分:2)

m有多大?

您可以执行以下操作:

create table two select null foo union all select null;
create temporary table seq ( foo int primary key auto_increment ) auto_increment=9 select a.foo from two a, two b, two c, two d;
select * from seq where foo <= 23;

其中auto_increment设置为n且where子句与m相比,两个表重复的次数至少为ceil(log(m-n + 1)/ log(2))。

(通过在create临时表seq中替换两个(select null foo union all select null)可以省略非临时两个表。)

答案 8 :(得分:2)

此查询生成0到1023之间的数字。我相信它适用于任何sql数据库风格:

select
     i0.i
    +i1.i*2
    +i2.i*4
    +i3.i*8
    +i4.i*16
    +i5.i*32
    +i6.i*64
    +i7.i*128
    +i8.i*256
    +i9.i*512
    as i
from
               (select 0 as i union select 1) as i0
    cross join (select 0 as i union select 1) as i1
    cross join (select 0 as i union select 1) as i2
    cross join (select 0 as i union select 1) as i3
    cross join (select 0 as i union select 1) as i4
    cross join (select 0 as i union select 1) as i5
    cross join (select 0 as i union select 1) as i6
    cross join (select 0 as i union select 1) as i7
    cross join (select 0 as i union select 1) as i8
    cross join (select 0 as i union select 1) as i9

答案 9 :(得分:2)

以下是其他答案中使用的技术的紧凑二进制版本:

select ((((((b7.0 << 1 | b6.0) << 1 | b5.0) << 1 | b4.0) 
                  << 1 | b3.0) << 1 | b2.0) << 1 | b1.0) << 1 | b0.0 as n
from (select 0 union all select 1) as b0,
     (select 0 union all select 1) as b1,
     (select 0 union all select 1) as b2,
     (select 0 union all select 1) as b3,
     (select 0 union all select 1) as b4,
     (select 0 union all select 1) as b5,
     (select 0 union all select 1) as b6,
     (select 0 union all select 1) as b7

没有唯一或排序阶段,没有字符串到数字转换,没有算术运算,每个虚拟表只有2行,所以它应该非常快。

此版本使用8&#34; bit&#34;因此它从0到255计数,但您可以轻松调整它。

答案 10 :(得分:1)

警告:如果您一次插入一行数字,您将最终执行N个命令,其中N是您需要插入的行数。

您可以使用临时表将此值降低到O(log N)(请参阅下面的插入10000到10699之间的数字):

mysql> CREATE TABLE `tmp_keys` (`k` INTEGER UNSIGNED, PRIMARY KEY (`k`));
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO `tmp_keys` VALUES (0),(1),(2),(3),(4),(5),(6),(7);
Query OK, 8 rows affected (0.03 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+8 from `tmp_keys`;
Query OK, 8 rows affected (0.02 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+16 from `tmp_keys`;
Query OK, 16 rows affected (0.03 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+32 from `tmp_keys`;
Query OK, 32 rows affected (0.03 sec)
Records: 32  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+64 from `tmp_keys`;
Query OK, 64 rows affected (0.03 sec)
Records: 64  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+128 from `tmp_keys`;
Query OK, 128 rows affected (0.05 sec)
Records: 128  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+256 from `tmp_keys`;
Query OK, 256 rows affected (0.03 sec)
Records: 256  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+512 from `tmp_keys`;
Query OK, 512 rows affected (0.11 sec)
Records: 512  Duplicates: 0  Warnings: 0

mysql> INSERT INTO inttable SELECT k+10000 FROM `tmp_keys` WHERE k<700;
Query OK, 700 rows affected (0.16 sec)
Records: 700  Duplicates: 0  Warnings: 0

编辑:fyi,遗憾的是,这不适用于真正的temporary table with MySQL 5.0,因为它无法插入到自身中(您可以在两个临时表之间来回反弹)。

编辑:您可以使用MEMORY storage engine来防止这实际上是对“真实”数据库的消耗。我想知道是否有人开发了一个“NUMBERS”虚拟存储引擎来实例化虚拟存储来创建这样的序列。 (唉,MySQL以外的不可移植)

答案 11 :(得分:1)

您似乎可以使用以下方法构建相当大的集:

select 9 union all select 10 union all select 11 union all select 12 union all select 13 ...

我在53.5的5.0.51a上有一个解析器堆栈溢出。

答案 12 :(得分:1)

最简单的方法是:

SET @seq := 0;
SELECT @seq := FLOOR(@seq + 1) AS sequence, yt.*
FROM your_table yt;

或在一个查询中:

SELECT @seq := FLOOR(@seq + 1) AS sequence, yt.*
FROM (SELECT @seq := 0) s, your_table yt;

此处使用FLOOR()函数来代替INTEGER来获取FLOAT。有时是必需的。

我的回答受到David Poor answer的启发。谢谢大卫!

答案 13 :(得分:1)

尝试这个..它在mysql版本8.0中对我有用。 您可以根据所需范围修改以下查询

WITH recursive numbers AS (
    select 0 as Date
   union all
   select Date + 1
   from numbers
   where Date < 10)
select * from numbers;

是的,并且没有创建帖子中提到的表格

答案 14 :(得分:0)

如果您使用的是Oracle,那么“流水线功能”将是您的最佳选择。不幸的是,MySQL没有这样的结构。

根据您想要的数字的比例,我看到两种简单的方法:您可以使用您需要的数字填充临时表(可能使用由存储过程填充的内存表)查询或预先构建一个从1到1,000,000的大表,并选择它的有界区域。

答案 15 :(得分:0)

计数器从1到1000:

  • 无需创建表
  • 执行时间〜0.0014秒
  • 可以转换为视图

select tt.row from
(
SELECT cast( concat(t.0,t2.0,t3.0,t4.0) + 1 As UNSIGNED) as 'row' FROM 
(select 0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t,
(select 0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2, 
(select 0 union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t3
) tt
order by tt.row

信用:answer,塞思·麦考利(Seth McCauley)在回答下方发表评论。

答案 16 :(得分:0)

with t1 as (
select 0 union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9
)
SELECT ROW_NUMBER() over ()
FROM
t1,
t1 as t2;

可以继续为 t1 表设置别名,无论您想要多大的表(10 的 n 次方)。然后可以添加一个极限X来切断它。