在MySQL中生成一个整数序列

我需要做一个表/结果集/任何具有整数n到m的连接。 有没有一个简单的方法来获得,而不只是build立表?

(顺便说一下,这种types的结构被称为“元查询”?)

mn是有限的(<1000's)

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

我在网上find了这个解决scheme

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

单个查询,快速,正是我想要的:现在我可以从一个复杂的查询中find的“select”,从1开始的唯一数字,并为结果中的每一行递增一次。

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

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

DDSP

以下将返回1..10000,并没有那么慢

 SELECT @row := @row + 1 as row FROM (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 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 3 union all select 4 union all select 5 union all select 6 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 3 union all select 4 union all select 5 union all select 6 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 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, (SELECT @row:=0) 

如果您碰巧使用MySQL的MariaDB分支 , 则SEQUENCE引擎允许直接生成数字序列。 它通过使用虚拟(假的)一个列表来完成。

例如,要生成从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,请考虑一下。

你可以尝试这样的事情:

 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提供一个相同的概念的工作的例子

有一种方法可以在单个查询中获得一系列值,但是有点慢。 它可以通过使用caching表来加快速度。

假设你想要一个所有BOOLEAN值范围的select:

 SELECT 0 as b UNION SELECT 1 as b; 

我们可以看看

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

那么你可以做一个Byte

 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; 

如果你需要一个date范围,你可以做。

 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'; 

请注意,这个技巧非常慢,只允许在预定义的域中创build有限序列(例如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是巨大的,只要你限制结果与限制1,30什么的。 一个COUNT(*)会花费很长时间,如果在MAX-MIN大于100K时添加ORDER BY会导致错误,那么将需要几秒钟来计算…

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比较,两个表重复的次数至less为ceil(log(m-n + 1)/ log(2))。

(在创build临时表序列中,可以省略两个非临时的两个表(select null foo union all select null)。

1到100.000之间的数字序列:

 SELECT e*10000+d*1000+c*100+b*10+an 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+an 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 

也许它有助于某人!

你似乎能够构build相当大的集合:

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

我在5.0.51a的5300上得到了一个parsing器堆栈溢出。

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

你可以通过使用一个临时表(见下面插入数字从10000到10699)到O(日志N):

 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,不幸的是,这不会使用MySQL 5.0的真正的临时表,因为它不能插入到自己(你可以在两个临时表之间来回跳动)。

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

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

 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 

没有唯一或sorting的阶段,没有string到数字的转换,也没有算术运算,每个虚拟表只有2行,所以它应该是相当快的。

这个版本使用8个“位”,所以它从0到255计数,但是你可以很容易地调整。

如果您使用的是Oracle,那么“stream水线function”就是要走的路。 不幸的是,MySQL没有这样的构造。

根据您想要设置的数字的大小,我看到了两个简单的方法:您可以使用一个查询填充只包含您需要的数字的临时表(可能使用由存储过程填充的内存表),或者,在前面,你build立一个从1到100万的大桌子,并select有限的区域。

这个查询生成从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