有没有一种方法可以生成任意数量的行,这些行可以在类似于 Oracle 语法的 JOIN 中使用:
SELECT LEVEL FROM DUAL CONNECT BY LEVEL<=10
讨厌这么说,但MySQL
它是RDBMS
四大中唯一没有此功能的。
在Oracle
:
SELECT *
FROM dual
CONNECT BY
level < n
在MS SQL
(最多100
行):
WITH hier(row) AS
(
SELECT 1
UNION ALL
SELECT row + 1
FROM hier
WHERE row < n
)
SELECT *
FROM hier
或使用提示32768
WITH hier(row) AS
(
SELECT 1
UNION ALL
SELECT row + 1
FROM hier
WHERE row < 32768
)
SELECT *
FROM hier
OPTION (MAXRECURSION 32767) -- 32767 is the maximum value of the hint
在PostgreSQL
:
SELECT *
FROM generate_series (1, n)
在MySQL
,什么都没有。
在 MySql 中,据我了解,您可以使用没有表(或 DUAL)的 SELECT 获得多行。
因此,要获得多行,您确实需要一个至少具有所需行数的真实表或临时表。
但是,您不需要构建临时表,因为您可以使用至少具有所需行数的任何现有表。因此,如果您的表至少具有所需的行数,请使用:
SELECT @curRow := @curRow + 1 AS row_number
FROM sometable
JOIN (SELECT @curRow := 0) r
WHERE @curRow<100;
只需将“sometable”替换为您的任何表的名称,至少具有所需的行数。
PS:“r”是表“别名”:我可以使用“AS r”。FROM 或 JOIN 子句中的任何子查询都会创建一个“派生表”,与所有表一样,该表必须具有名称或别名。(见 MySql 手册:13.2.9.8. FROM 子句中的子查询)
由于这是目前 Google 中“mysql 行生成器”的首批结果之一,因此我将添加一个更新。
如果你喜欢的 MySQL 恰好是 MariaDB,那么它们就有这个特性。它被称为“序列存储引擎”,它的使用方式如下:
select * from seq_1_to_10;
结果:
+-----+
| seq |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+-----+
10 rows in set (0.00 sec)
在 10.0 版本之前,它是一个需要显式安装的单独插件,但从 10.0 开始,它是内置的。享受吧!
在 MySQL 8.0、MariaDB 10.2 和更高版本中,您可以使用递归 CTE:
WITH RECURSIVE sequence AS (
SELECT 1 AS level
UNION ALL
SELECT level + 1 AS value
FROM sequence
WHERE sequence.level < 10
)
SELECT level
FROM sequence;
请注意,CTEcte_max_recursion_depth
在 MySQL 中受(默认 1000,最大 4,294,967,295 (2³²−1))和max_recursive_iterations
MariaDB 中(默认 4,294,967,295)的限制。
您可以通过执行来增加限制:
SET cte_max_recursion_depth = 4294967295;
它只会影响您当前的会话并且不会被持久化。
对于 8.0 之前的 MySQL 版本,您可以使用以下Markus Winand的巧妙技巧:
CREATE OR REPLACE VIEW generator_16
AS SELECT 0 n 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 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL
SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL
SELECT 15;
CREATE OR REPLACE VIEW generator_256
AS SELECT ( ( hi.n << 4 ) | lo.n ) AS n
FROM generator_16 lo, generator_16 hi;
CREATE OR REPLACE VIEW generator_4k
AS SELECT ( ( hi.n << 8 ) | lo.n ) AS n
FROM generator_256 lo, generator_16 hi;
CREATE OR REPLACE VIEW generator_64k
AS SELECT ( ( hi.n << 8 ) | lo.n ) AS n
FROM generator_256 lo, generator_256 hi;
CREATE OR REPLACE VIEW generator_1m
AS SELECT ( ( hi.n << 16 ) | lo.n ) AS n
FROM generator_64k lo, generator_16 hi;
CREATE OR REPLACE VIEW generator_16m
AS SELECT ( ( hi.n << 16 ) | lo.n ) AS n
FROM generator_64k lo, generator_256 hi;
CREATE OR REPLACE VIEW generator_4b
AS SELECT ( ( hi.n << 16 ) | lo.n ) AS n
FROM generator_64k lo, generator_64k hi;
进而:
SELECT n FROM generator_4b limit 10;
在我的笔记本电脑上创建 even 只需要大约 20 毫秒generator_4b
,其中包含超过 40 亿行。上面所有的生成器视图加起来只占用 28 KB 的存储空间。
如果你想知道它是如何工作的,你可以在他的博文中找到详细的解释。
c5
我有一个包含数字 x的列 ( ) 的表,我需要一个重复相同行 x 次的 SQL 表达式。
我的表 A 包含:
c1 c2 c3 c4 c5
16 1 2 16 3
16 1 2 17 2
16 1 2 18 1
我需要:
c1 c2 c3 c4 c5 n
16 1 2 16 3 1
16 1 2 16 3 2
16 1 2 16 3 3
16 1 2 17 2 1
16 1 2 17 2 2
16 1 2 18 1 1
我用表达式解决了这个问题:
SELECT
c1, c2, c3, c4, c5, row_number AS n
FROM
(
SELECT
@curRow := @curRow + 1 AS row_number
FROM
tablea
JOIN (SELECT @curRow := 0) r
WHERE
@curRow < (
SELECT
max(field1)
FROM
tablea
)
) AS vwtable2
LEFT JOIN tablea d ON vwtable2.row_number <= tablea.field1;
如果我理解你,你想要一个连续数字的列表吗?
只需列出清单:
create table artificial_range (id int not null primary key auto_increment, idn int);
insert into artificial_range (idn) values (0); --first row
insert into artificial_range(idn) select idn from artificial_range; --2nd
insert into artificial_range(idn) select idn from artificial_range; -- now 4 rows
insert into artificial_range(idn) select idn from artificial_range; --8
insert into artificial_range(idn) select idn from artificial_range; --16
insert into artificial_range(idn) select idn from artificial_range; --32
insert into artificial_range(idn) select idn from artificial_range; --64
insert into artificial_range(idn) select idn from artificial_range; --128
...等等,直到你有,比如说,1024。
update artificial_range set idn = id - 1 ;
-- 现在你有一个从 1 (id) 开始的系列和一个从 0 开始的系列
现在加入它,或加入它的转换:
create view days_this_century as
select date_add('2000-01-01', interval a.idn day) as cdate
from artificial_range;
我不知道这是否有帮助,但您可以使用 sth 对每个 select 语句中的行进行编号。像:
设置@NUM = 0;
SELECT @NUM:=@NUM+1 行号,* FROM ...
后来加入他们的行列。在大型数据库中,这可能非常慢。
要生成 10 行:
SELECT a AS 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 from dual
您可以生成 100 行与另外 10 行进行连接:
select t2.a*10 + t1.a from
(SELECT 0 AS 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 AS 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) t2
然后 1000 行与另一个连接,...
可以,但是有点麻烦
这里是:
mysql> create table t(inc bigint primary key auto_increment);
Query OK, 0 rows affected (0.03 sec)
mysql> insert into t values(0);
Query OK, 1 row affected (0.01 sec)
mysql> insert into t select 0 from t;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into t select 0 from t;
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into t select 0 from t;
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> insert into t select 0 from t;
Query OK, 8 rows affected (0.01 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> select count(inc), max(inc) from t;
+------------+----------+
| count(inc) | max(inc) |
+------------+----------+
| 16 | 20 |
+------------+----------+
1 row in set (0.00 sec)
mysql> select row_number() over w as inc from t window w as (order by inc);
+-----+
| inc |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
+-----+
16 rows in set (0.00 sec)
您可以通过发出语句将生成的行数加倍
insert into t select 0 from t;
尽可能多的。
另请注意,默认情况下auto_increment会产生一些间隙,这就是使用row_number()的原因。