Generate an integer sequence in MySQL

前端 未结 16 2696
南旧
南旧 2020-11-22 06:47

I need to do a join with a table/result-set/whatever that has the integers n to m inclusive. Is there a trivial way to get that without just buildi

相关标签:
16条回答
  • 2020-11-22 07:29

    The following will return 1..10000 and is not so slow

    SELECT @row := @row + 1 AS row FROM 
    (select 0 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) t,
    (select 0 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, 
    (select 0 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) t3, 
    (select 0 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) t4, 
    (SELECT @row:=0) numbers;
    
    0 讨论(0)
  • 2020-11-22 07:29

    Here is a compact binary version of the technique used in other answers here:

    select ((((((b7.0 << 1 | b6.0) << 1 | b5.0) << 1 | b4.0) 
                      << 1 | b3.0) << 1 | b2.0) << 1 | b1.0) << 1 | b0.0 as n
    from (select 0 union all select 1) as b0,
         (select 0 union all select 1) as b1,
         (select 0 union all select 1) as b2,
         (select 0 union all select 1) as b3,
         (select 0 union all select 1) as b4,
         (select 0 union all select 1) as b5,
         (select 0 union all select 1) as b6,
         (select 0 union all select 1) as b7
    

    There are no unique or sorting phases, no string to number conversion, no arithmetic operations, and each dummy table only has 2 rows, so it should be pretty fast.

    This version uses 8 "bits" so it counts from 0 to 255, but you can easily tweak that.

    0 讨论(0)
  • 2020-11-22 07:31

    The simplest way to do this is:

    SET @seq := 0;
    SELECT @seq := FLOOR(@seq + 1) AS sequence, yt.*
    FROM your_table yt;
    

    or in one query:

    SELECT @seq := FLOOR(@seq + 1) AS sequence, yt.*
    FROM (SELECT @seq := 0) s, your_table yt;
    

    The FLOOR() function is used here to get an INTEGER in place of a FLOAT. Sometimes it is needed.

    My answer was inspired by David Poor answer. Thanks David!

    0 讨论(0)
  • 2020-11-22 07:32

    There is a way to get a range of values in a single query, but its a bit slow. It can be sped up by using cache tables.

    assume you want a select with a range of all BOOLEAN values:

    SELECT 0 as b UNION SELECT 1 as b;
    

    we can make a view

    CREATE VIEW ViewBoolean AS SELECT 0 as b UNION SELECT 1 as b;
    

    then you can do a Byte by

    CREATE VIEW ViewByteValues AS
    SELECT b0.b + b1.b*2 + b2.b*4 + b3.b*8 + b4.b*16 + b5.b*32 + b6.b*64 + b7.b*128 as v FROM
    ViewBoolean b0,ViewBoolean b1,ViewBoolean b2,ViewBoolean b3,ViewBoolean b4,ViewBoolean b5,ViewBoolean b6,ViewBoolean b7;
    

    then you can do a

    CREATE VIEW ViewInt16 AS
    SELECT b0.v + b1.v*256 as v FROM
    ViewByteValues b0,ViewByteValues b1;
    

    then you can do a

    SELECT v+MIN as x FROM ViewInt16 WHERE v<MAX-MIN;
    

    To speed this up I skipped the auto-calculation of byte values and made myself a

    CREATE VIEW ViewByteValues AS
    SELECT 0 as v UNION SELECT 1 as v UNION SELECT ...
    ...
    ...254 as v UNION SELECT 255 as v;
    

    If you need a range of dates you can do.

    SELECT DATE_ADD('start_date',v) as day FROM ViewInt16 WHERE v<NumDays;
    

    or

    SELECT DATE_ADD('start_date',v) as day FROM ViewInt16 WHERE day<'end_date';
    

    you might be able to speed this up with the slightly faster MAKEDATE function

    SELECT MAKEDATE(start_year,1+v) as day FRON ViewInt16 WHERE day>'start_date' AND day<'end_date';
    

    Please note that this tricks are VERY SLOW and only allow the creation of FINITE sequences in a pre-defined domain (for example int16 = 0...65536 )

    I am sure you can modify the queries a bit to speed things up by hinting to MySQL where to stop calculating ;) (using ON clauses instead of WHERE clauses and stuff like that)

    For example:

    SELECT MIN + (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) FROM
    ViewByteValues b0,
    ViewByteValues b1,
    ViewByteValues b2,
    ViewByteValues b3
    WHERE (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) < MAX-MIN;
    

    will keep your SQL server busy for a few hours

    However

    SELECT MIN + (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) FROM
    ViewByteValues b0
    INNER JOIN ViewByteValues b1 ON (b1.v*256<(MAX-MIN))
    INNER JOIN ViewByteValues b2 ON (b2.v*65536<(MAX-MIN))
    INNER JOIN ViewByteValues b3 ON (b3.v*16777216<(MAX-MIN)
    WHERE (b0.v + b1.v*256 + b2.v*65536 + b3.v*16777216) < (MAX-MIN);
    

    will run reasonably fast - even if MAX-MIN is huge as long as you limit the result with LIMIT 1,30 or something. a COUNT(*) however will take ages and if you make the mistake of adding ORDER BY when MAX-MIN is bigger than say 100k it will again take several seconds to calculate...

    0 讨论(0)
提交回复
热议问题