如何在MySQL中创建行生成器?

时间:2009-03-31 15:04:15

标签: sql mysql generator

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

SELECT LEVEL FROM DUAL CONNECT BY LEVEL<=10

9 个答案:

答案 0 :(得分:25)

讨厌这样说,但是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中,没有。

答案 1 :(得分:13)

在MySql中,我理解你可以使用没有表(或DUAL)的SELECT获得多行。

因此,要获取多行,您执行需要一个至少包含所需行数的实际或临时表。

但是,您不需要构建临时表,因为您可以使用 ANY 现有表,该表至少具有所需的行数。因此,如果您的表格至少包含所需的行数,请使用:

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

答案 2 :(得分:3)

由于这是Google目前“mysql行生成器”的第一个结果,我将添加更新。

如果您的MySQL风味恰好是MariaDB,他们就有这个功能。它被称为"Sequence Storage engine",它的用法如下:

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开始它内置。享受!

答案 3 :(得分:2)

我有一个包含数字x的列(c5)的表,我需要一个重复相同行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;

答案 4 :(得分:2)

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;

请注意,在MySQL中,CTE受cte_max_recursion_depth(默认为1000,最大为4,294,967,295(2³²−1))的限制,而在MariaDB中,受max_recursive_iterations(默认为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;

在我的笔记本电脑上,创建generator_4b只需花费约20毫秒,其中{ "compilerOptions": { "target": "es2017", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react" }, "include": [ "src" ], } 包含40亿行。而且上述所有生成器视图的总存储空间仅为28 KB。

如果您想知道它是如何工作的,可以在他的blog post中找到详细的说明。

答案 5 :(得分: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;

答案 6 :(得分:0)

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

  

SET @NUM = 0;

     

SELECT @NUM:= @ NUM + 1 rowNumber,* FROM   ...

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

答案 7 :(得分: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行并添加另一个连接...

答案 8 :(得分: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()的原因。