在MySQL中生成一系列数字

时间:2008-10-09 11:03:41

标签: sql mysql

如何从MySQL查询中生成一系列连续数字(每行一个),以便我可以将它们插入表格中?

例如:

nr
1
2
3
4
5

我想只使用MySQL(不是PHP或其他语言)。

13 个答案:

答案 0 :(得分:60)

这是一种基于集合的方法,没有循环。这也可以作为重复使用的视图。该示例显示了从0到999的序列的生成,但当然,可以修改它以适应。

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

答案 1 :(得分:47)

这是硬件工程师的Pittsburgh DBA's solution版本:

SELECT
    (TWO_1.SeqValue + TWO_2.SeqValue + TWO_4.SeqValue + TWO_8.SeqValue + TWO_16.SeqValue) SeqValue
FROM
    (SELECT 0 SeqValue UNION ALL SELECT 1 SeqValue) TWO_1
    CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 2 SeqValue) TWO_2
    CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 4 SeqValue) TWO_4
    CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 8 SeqValue) TWO_8
    CROSS JOIN (SELECT 0 SeqValue UNION ALL SELECT 16 SeqValue) TWO_16;

答案 2 :(得分:28)

如果您需要表中的记录并且希望避免并发问题,请按照以下步骤操作。

首先,您要创建一个用于存储记录的表

CREATE TABLE `incr` (
  `Id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`Id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

其次创建一个这样的存储过程:

DELIMITER ;;
CREATE PROCEDURE dowhile()
BEGIN
  DECLARE v1 INT DEFAULT 5;
  WHILE v1 > 0 DO
    INSERT incr VALUES (NULL);
    SET v1 = v1 - 1;
  END WHILE;
END;;
DELIMITER ;

最后致电SP:

CALL dowhile();
SELECT * FROM incr;

结果

Id
1
2
3
4
5

答案 3 :(得分:13)

我们假设您要在表格中插入数字1到100。只要你有一些其他表至少包含那么多行(表格的内容并不重要),那么这是我首选的方法:

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

想要一个以1以外的东西开头的范围?只需更改@ROW在连接上设置的内容。

答案 4 :(得分:5)

DECLARE i INT DEFAULT 0;

WHILE i < 6 DO
  /* insert into table... */
  SET i = i + 1;
END WHILE;

答案 5 :(得分:5)

大家都明白,这是相当黑客的,所以要小心使用

SELECT id % 12 + 1 as one_to_twelve FROM any_large_table group by one_to_twelve

答案 6 :(得分:0)

我知道(在MySQL中)创建具有长序列的表的“最短”方式是(交叉)将现有表与其自身连接。由于任何(常见的)MySQL服务器都有information_schema.COLUMNS表,我会使用它:

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

通常一个连接应该足以创建超过1M的行 - 但是还有一个连接不会受到影响:-) - 只是不要忘记设置限制。

如果您想加入0,则应“删除”AUTO_INCEMENT媒体资源。

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

现在您可以插入0

INSERT INTO seq (i) VALUES (0);

和负数

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

您可以使用

验证号码
SELECT MIN(i), MAX(i), COUNT(*) FROM seq;

答案 7 :(得分:0)

我想分享的想法不是对问题的准确回答,但对某些人有用,所以我想分享它。

如果您经常只需要一组有限的数字,那么创建一个包含您可能需要的数字的表格并且每次只使用该表格都是有益的。例如:

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

仅当您需要低于某个合理限制的数字时才能应用此功能,因此不要将其用于生成序列1 ... 1百万,但可用于数字1 ... 10k,例如。

如果您在_numbers表中有这个数字列表,那么您可以编写这样的查询,以获取字符串的各个字符:

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

如果您需要的数字大于10k,那么您可以将表格加入到自身:

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

答案 8 :(得分:0)

与接受的响应非常相似,但是对mysql> = 8.0使用了新的WITH语法,这使它更加清晰易读,意图也更加清晰

WITH DIGITS (N) AS (
  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)
SELECT 
  UNITS.N + TENS.N*10 + HUNDREDS.N*100 + THOUSANDS.N*1000 
FROM 
  DIGITS AS UNITS, DIGITS AS TENS, DIGITS AS HUNDREDS, DIGITS AS THOUSANDS;

答案 9 :(得分:0)

这基于先前的答案(https://stackoverflow.com/a/53125278/2009581),但与MySQL 5.7兼容。它适用于副本和只读用户:

var city = {};

$('.ville-select option').each(function() {
  var val = $(this).val();
  if (city[val]) {
    $(this).remove();
    return;
  }
  city[val] = 1;
});

它会生成[0,SELECT x1.N + x10.N*10 + x100.N*100 + x1000.N*1000 FROM (SELECT 0 AS 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) x1, (SELECT 0 AS 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) x10, (SELECT 0 AS 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) x100, (SELECT 0 AS 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) x1000 WHERE x1.N + x10.N*10 + x100.N*100 + x1000.N*1000 <= @max; ]范围内的整数。

答案 10 :(得分:0)

所有其他答案都不错,但是它们都存在较大范围的速度问题,因为它们迫使MySQL生成每个数字然后对其进行过滤。

以下内容仅使MySQL生成所需的数字,因此速度更快:

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;

使用上述方法,您最多可以生成10,000个数字(0到9,999),而对于较低的数字,无论它们有多低,都不会降低速度。

答案 11 :(得分:0)

如果您有 MySql 8 及更高版本,这里有一种使用 json_table 的方法:

set @noRows = 100;
SELECT tt.rowid - 1 AS value
  FROM JSON_TABLE(CONCAT('[{}', REPEAT(',{}', @noRows - 1), ']'),
                  "$[*]" COLUMNS(rowid FOR ORDINALITY)
       ) AS tt; 

(h/t - https://www.percona.com/blog/2020/07/27/generating-numeric-sequences-in-mysql/)

答案 12 :(得分:0)

使用递归 cte..

  with recursive rnums as (
  select 1 as n
      union all
  select n+1 as n from rnums
      where n <10
  )
  select * from rnums
  ;

结果是.. +------+ | | | +------+ | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | | 10 | +------+ 10 行(0.00 秒)