Generating a range of numbers in MySQL

前端 未结 11 1757
一个人的身影
一个人的身影 2020-11-22 15:07

How do I generate a range of consecutive numbers (one per line) from a MySQL query so that I can insert them into a table?

For example:

nr
1
2
3
4
5
         


        
相关标签:
11条回答
  • 2020-11-22 15:43

    The "shortest" way i know (in MySQL) to create a table with a long sequence is to (cross) join an existing table with itself. Since any (common) MySQL server has the information_schema.COLUMNS table i would use it:

    DROP TABLE IF EXISTS seq;
    CREATE TABLE seq (i MEDIUMINT AUTO_INCREMENT PRIMARY KEY)
        SELECT NULL AS i
        FROM information_schema.COLUMNS t1
        JOIN information_schema.COLUMNS t2
        JOIN information_schema.COLUMNS t3
        LIMIT 100000; -- <- set your limit here
    

    Usually one join should be enough to create over 1M rows - But one more join will not hurt :-) - Just don't forget to set a limit.

    If you want to include 0, you should "remove" the AUTO_INCEMENT property.

    ALTER TABLE seq ALTER i DROP DEFAULT;
    ALTER TABLE seq MODIFY i MEDIUMINT;
    

    Now you can insert 0

    INSERT INTO seq (i) VALUES (0);
    

    and negative numbers as well

    INSERT INTO seq (i) SELECT -i FROM seq WHERE i <> 0;
    

    You can validate the numbers with

    SELECT MIN(i), MAX(i), COUNT(*) FROM seq;
    
    0 讨论(0)
  • 2020-11-22 15:47

    Let's say you want to insert numbers 1 through 100 into your table. As long as you have some other table that has at least that many rows (doesn't matter the content of the table), then this is my preferred method:

    INSERT INTO pivot100 
    SELECT @ROW := @ROW + 1 AS ROW
     FROM someOtherTable t
     join (SELECT @ROW := 0) t2
     LIMIT 100
    ;
    

    Want a range that starts with something other than 1? Just change what @ROW gets set to on the join.

    0 讨论(0)
  • 2020-11-22 15:51

    As you all understand, this is rather hacky so use with care

    SELECT id % 12 + 1 as one_to_twelve FROM any_large_table group by one_to_twelve
    
    0 讨论(0)
  • 2020-11-22 15:52

    All other answers are good, however they all have speed issues for larger ranges because they force MySQL to generate every number then filter them.

    The following only makes MySQL generate the numbers that are needed, and therefore is faster:

    set @amount = 55; # How many numbers from zero you want to generate
    
    select `t0`.`i`+`t1`.`i`+`t2`.`i`+`t3`.`i` as `offset`
    from
    (select 0 `i` union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) `t0`,
    (select 0 `i` union select 10 union select 20 union select 30 union select 40 union select 50 union select 60 union select 70 union select 80 union select 90) `t1`,
    (select 0 `i` union select 100 union select 200 union select 300 union select 400 union select 500 union select 600 union select 700 union select 800 union select 900) `t2`,
    (select 0 `i` union select 1000 union select 2000 union select 3000 union select 4000 union select 5000 union select 6000 union select 7000 union select 8000 union select 9000) `t3`
    where `t3`.`i`<@amount
    and `t2`.`i`<@amount
    and `t1`.`i`<@amount
    and `t0`.`i`+`t1`.`i`+`t2`.`i`+`t3`.`i`<@amount;
    

    With the above you can generate upto 10,000 numbers (0 to 9,999) with no slower speed overhead for lower numbers, regardless how low they are.

    0 讨论(0)
  • 2020-11-22 15:54

    Here is one way to do it set-based without loops. This can also be made into a view for re-use. The example shows the generation of a sequence from 0 through 999, but of course, it may be modified to suit.

    INSERT INTO
        myTable
        (
        nr
        )
    SELECT
        SEQ.SeqValue
    FROM
    (
    SELECT
        (HUNDREDS.SeqValue + TENS.SeqValue + ONES.SeqValue) SeqValue
    FROM
        (
        SELECT 0  SeqValue
        UNION ALL
        SELECT 1 SeqValue
        UNION ALL
        SELECT 2 SeqValue
        UNION ALL
        SELECT 3 SeqValue
        UNION ALL
        SELECT 4 SeqValue
        UNION ALL
        SELECT 5 SeqValue
        UNION ALL
        SELECT 6 SeqValue
        UNION ALL
        SELECT 7 SeqValue
        UNION ALL
        SELECT 8 SeqValue
        UNION ALL
        SELECT 9 SeqValue
        ) ONES
    CROSS JOIN
        (
        SELECT 0 SeqValue
        UNION ALL
        SELECT 10 SeqValue
        UNION ALL
        SELECT 20 SeqValue
        UNION ALL
        SELECT 30 SeqValue
        UNION ALL
        SELECT 40 SeqValue
        UNION ALL
        SELECT 50 SeqValue
        UNION ALL
        SELECT 60 SeqValue
        UNION ALL
        SELECT 70 SeqValue
        UNION ALL
        SELECT 80 SeqValue
        UNION ALL
        SELECT 90 SeqValue
        ) TENS
    CROSS JOIN
        (
        SELECT 0 SeqValue
        UNION ALL
        SELECT 100 SeqValue
        UNION ALL
        SELECT 200 SeqValue
        UNION ALL
        SELECT 300 SeqValue
        UNION ALL
        SELECT 400 SeqValue
        UNION ALL
        SELECT 500 SeqValue
        UNION ALL
        SELECT 600 SeqValue
        UNION ALL
        SELECT 700 SeqValue
        UNION ALL
        SELECT 800 SeqValue
        UNION ALL
        SELECT 900 SeqValue
        ) HUNDREDS
    ) SEQ
    
    0 讨论(0)
  • 2020-11-22 15:55

    The idea I want to share is not a precise response for the question but can be useful for some so I would like to share it.

    If you frequently need only a limited set of numbers then it can be beneficial to create a table with the numbers you may need and just use that table every time. For example:

    CREATE TABLE _numbers (num int);
    INSERT _numbers VALUES (0), (1), (2), (3), ...;
    

    This can be applied only if you need numbers below a certain reasonable limit, so don't use it for generating sequence 1...1 million but can be used for numbers 1...10k, for example.

    If you have this list of numbers in the _numbers table then you can write queries like this, for obtaining the individual characters of a string:

    SELECT number, substr(name, num, 1) 
        FROM users
        JOIN _numbers ON num < length(name)
        WHERE user_id = 1234
        ORDER BY num;
    

    If you need larger numbers than 10k then you can join the table to itself:

    SELECT n1.num * 10000 + n2.num
        FROM _numbers n1
        JOIN _numbers n2
        WHERE n1 < 100 
        ORDER BY n1.num * 10000 + n2.num; -- or just ORDER BY 1 meaning the first column
    
    0 讨论(0)
提交回复
热议问题