29

有没有一种方法可以生成任意数量的行,这些行可以在类似于 Oracle 语法的 JOIN 中使用:

SELECT LEVEL FROM DUAL CONNECT BY LEVEL<=10
4

9 回答 9

31

讨厌这么说,但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,什么都没有。

于 2009-04-01T15:24:17.867 回答
19

在 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 子句中的子查询)

于 2013-09-29T20:24:46.517 回答
11

由于这是目前 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 开始,它是内置的。享受吧!

于 2018-03-23T09:26:15.497 回答
8

MySQL 8.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_iterationsMariaDB 中(默认 4,294,967,295)的限制。

您可以通过执行来增加限制:

SET cte_max_recursion_depth = 4294967295;

它只会影响您当前的会话并且不会被持久化。

MySQL 5.7、5.6 及更低版本

对于 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 的存储空间。

如果你想知道它是如何工作的,你可以在他的博文中找到详细的解释。

于 2020-04-12T09:41:51.597 回答
2

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;
于 2015-10-21T20:08:33.933 回答
1

如果我理解你,你想要一个连续数字的列表吗?

只需列出清单:

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;
于 2009-04-02T00:14:30.087 回答
0

我不知道这是否有帮助,但您可以使用 sth 对每个 select 语句中的行进行编号。像:

设置@NUM = 0;

SELECT @NUM:=@NUM+1 行号,* FROM ...

后来加入他们的行列。在大型数据库中,这可能非常慢。

于 2009-04-01T15:19:38.627 回答
0

要生成 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 行与另一个连接,...

于 2019-02-08T14:34:47.740 回答
0

可以,但是有点麻烦

这里是:

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()的原因。

于 2020-03-11T05:46:23.690 回答