Генерация диапазона чисел в MySQL - PullRequest
44 голосов
/ 09 октября 2008

Как мне сгенерировать диапазон последовательных чисел (по одному в строке) из запроса MySQL, чтобы я мог вставить их в таблицу?

Например:

nr
1
2
3
4
5

Я хотел бы использовать для этого только MySQL (не PHP или другие языки).

Ответы [ 9 ]

60 голосов
/ 09 октября 2008

Вот один из способов сделать это на основе множества без циклов. Это также может быть сделано для повторного использования. В этом примере показана генерация последовательности от 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
47 голосов
/ 02 декабря 2011

Вот версия аппаратного инженера Решение DBS Питсбурга :

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;
28 голосов
/ 09 октября 2008

Если вам нужны записи в таблице и вы хотите избежать проблем с параллелизмом, вот как это сделать.

Сначала вы создаете таблицу для хранения ваших записей

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 ;

Наконец, позвоните ИП:

CALL dowhile();
SELECT * FROM incr;

Результат

Id
1
2
3
4
5
13 голосов
/ 14 декабря 2011

Допустим, вы хотите вставить числа от 1 до 100 в вашу таблицу. Пока у вас есть какая-то другая таблица, в которой есть хотя бы столько строк (не имеет значения содержимое таблицы), тогда это мой предпочтительный метод:

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

Хотите диапазон, который начинается с чего-то, кроме 1? Просто измените настройку @ROW в соединении.

5 голосов
/ 22 января 2014

Как вы все понимаете, это довольно глупо, поэтому используйте с осторожностью

SELECT id % 12 + 1 as one_to_twelve FROM any_large_table group by one_to_twelve
5 голосов
/ 09 октября 2008
DECLARE i INT DEFAULT 0;

WHILE i < 6 DO
  /* insert into table... */
  SET i = i + 1;
END WHILE;
0 голосов
/ 02 ноября 2018

Очень похоже на принятый ответ, но с использованием нового синтаксиса WITH для mysql> = 8.0, что делает его более разборчивым, а цель также более ясной

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;
0 голосов
/ 15 февраля 2018

Идея, которой я хочу поделиться, не является точным ответом на вопрос, но может быть полезна для некоторых, поэтому я хотел бы поделиться ею.

Если вам часто требуется только ограниченный набор чисел, то может быть полезно создать таблицу с числами, которые вам могут понадобиться, и просто использовать эту таблицу каждый раз. Например:

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
0 голосов
/ 05 марта 2017

«Самый короткий» способ, которым я знаю (в 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

Обычно одного объединения должно быть достаточно для создания более 1М строк - но еще одно объединение не повредит :-) - Просто не забудьте установить ограничение.

Если вы хотите включить 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...