How do I make a row generator in MySQL?
Question
Is there a way to generate an arbitrary number of rows that can be used in a JOIN similar to the Oracle syntax:
SELECT LEVEL FROM DUAL CONNECT BY LEVEL<=10
Solution
Hate to say this, but MySQL
is the only RDBMS
of the big four that doesn't have this feature.
In Oracle
:
SELECT *
FROM dual
CONNECT BY
level < n
In MS SQL
(up to 100
rows):
WITH hier(row) AS
(
SELECT 1
UNION ALL
SELECT row + 1
FROM hier
WHERE row < n
)
SELECT *
FROM hier
or using hint up to 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
In PostgreSQL
:
SELECT *
FROM generate_series (1, n)
In MySQL
, nothing.
OTHER TIPS
In MySql, it is my understand that you can get more than one row with a SELECT with no table (or DUAL).
Therefore, to get multiple rows, you do need a real or temporary table with at least the required number of rows.
However, you do not need to build a temporary table as you can use ANY existing table which has at least the number of rows required. So, if you have a table with at least the required number of rows, use:
SELECT @curRow := @curRow + 1 AS row_number
FROM sometable
JOIN (SELECT @curRow := 0) r
WHERE @curRow<100;
Just replace "sometable" with the name of any table of yours with at least the required number of rows.
PS: The "r" is a table "alias": I could have used "AS r". Any subquery in a FROM or JOIN clause creates a "derived table" which, as with all tables, must have a name or alias. (See MySql manual: 13.2.9.8. Subqueries in the FROM Clause)
Since this is currently one of the first results in Google for "mysql row generator", I'll add an update.
If your flavor of MySQL happens to be MariaDB, they have this feature. It's called the "Sequence Storage engine" and it's used like this:
select * from seq_1_to_10;
With the results:
+-----+
| seq |
+-----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
+-----+
10 rows in set (0.00 sec)
Until version 10.0 it was a separate plugin that needed to be explicitly installed, but from 10.0 onwards it's built in. Enjoy!
I had a table with a column (c5
) that contained a number x, I needed a SQL expression that repeated the same row x numbers of times.
My table A contained:
c1 c2 c3 c4 c5
16 1 2 16 3
16 1 2 17 2
16 1 2 18 1
And I needed:
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
I solved that with the expression:
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;
If I'm understanding you, you want a list of consequtive numbers?
Just make the list:
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
... etc, until you have, say, 1024.
update artificial_range set idn = id - 1 ;
-- now you have a series staring at 1 (id) and a series starting at 0
Now join to it, or join to transformations of it:
create view days_this_century as
select date_add('2000-01-01', interval a.idn day) as cdate
from artificial_range;
I don't know if this helps but you can number the rows from each select statement with sth. like:
SET @NUM = 0;
SELECT @NUM:=@NUM+1 rowNumber, * FROM ...
And later join them on this one. At large databases this can be very slow.
To generate 10 rows:
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
You can generate 100 rows making a join with another 10 rows:
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
And then 1000 rows with another join, ...