0

I'd like to generate a sequence in MariaDB starting at 1 and ending with whatever is the largest id in some other table. That other table has roughly this schema:

create table main (
 id integer primary key,
 -- ... other columns --
);

I've learned about MariaDB STORAGE engine for generating sequences but on the surface that's good only for generating static sequences, where you know the range at the time of writing the query, e.g.

MariaDB [skynetdb]> select * from seq_1_to_3;
+-----+
| seq |
+-----+
| 1 |
| 2 |
| 3 |
+-----+
3 rows in set (0.001 sec)

But how do I generate sequence whose upper bound is the result of select max(id) from main? It seems that MariaDB doesn't accept meta-queries where I would construct a name of a table to query and then query it in a single query, e.g. something like this:

-- INVALID, FOR ILLUSTRATION ONLY
select * from concat('seq_1_to_', select max(id) from main)

Or is it possible? How? (Note I'm aware that I can do one additional roundtrip and construct the sequence table name on the client, but I want to avoid it because I don't have a feature rich client, only mysql command)


The following recursive common table expression (CTE) works

MariaDB [skynetdb]> with recursive nums(n) as (select 1 union all select n+1 from nums where n <= (select max(id) from main)) select * from nums;

but it's too slow. It seems it constructs whole nums table in memory first.

asked Mar 19, 2020 at 17:55
1
  • 1
    You can use a prepared statement that concatenates strings first. Commented Mar 19, 2020 at 20:01

1 Answer 1

1
SELECT seq
 FROM seq_0_to_99999999
 WHERE seq BETWEEN 12345678 and 12345688;

works fine and fast. It returned 11 rows.

A more complex query:

SELECT MIN(FROM_DAYS(seq)) AS first_day,
 MAX(FROM_DAYS(seq)) AS last_day,
 COUNT(*) AS number_of_days
 FROM seq_0_to_99999999
 WHERE seq BETWEEN TO_DAYS('2020-01-01')
 AND TO_DAYS(CURDATE());

Returned:

+------------+------------+----------------+
| first_day | last_day | number_of_days |
+------------+------------+----------------+
| 2020年01月01日 | 2020年04月02日 | 93 |
+------------+------------+----------------+
1 row in set (0.00 sec)

It, too, was fast, and touched only 94 rows according to the 'Handler_read%' values. Cf: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#handler_counts

For your case, you may need something like

WHERE seq BETWEEN ...
 AND ( SELECT MAX(...) FROM ... )

I find that the general use of seq is to generate a generous number of values, then let WHERE go for the range I need. The Optimizer avoids really generating the zillion values I seem to be asking for. (At least in examples like these.)

answered Apr 2, 2020 at 0:03

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.