Сгенерируйте целочисленную последовательность в MySQL

Мне нужно выполнить соединение с таблицей / набором результатов / всем, что имеет целые числа от n до m включительно. Есть ли простой способ добиться этого, не создавая таблицы?

(Кстати, как бы этот тип конструкции назывался «Мета-запрос»?)

m-n ограничен чем-то разумным (<1000)

у вас могут возникнуть проблемы с auto_increment, когда нужно включить родительский и дочерний элементы одновременно, я никогда не использую его, nextval проще. Вы можете увидеть функцию nextval для кода mysql здесь: stackoverflow.com/questions/8058675/…

user1041554 11.11.2011 15:02
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для разработчиков
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
65
1
143 848
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Ответ принят как подходящий

В MySQL нет генератора порядковых номеров (СОЗДАТЬ ПОСЛЕДОВАТЕЛЬНОСТЬ). Самая близкая вещь - AUTO_INCREMENT, которая может помочь вам составить таблицу.

До сих пор MySQL 8 не поддерживает эту функцию. Он был реализован в MariaDB и PostgreSQL.

Mahoor13 10.01.2021 09:44

Насколько большой м?

Вы можете сделать что-то вроде:

create table two select null foo union all select null;
create temporary table seq ( foo int primary key auto_increment ) auto_increment=9 select a.foo from two a, two b, two c, two d;
select * from seq where foo <= 23;

где auto_increment имеет значение n, а предложение where сравнивается с m, а количество повторений двух таблиц составляет не менее ceil (log (m-n + 1) / log (2)).

(Невременные две таблицы могут быть опущены, заменив две на (выберите null foo union all select null) в последовательности создания временной таблицы.)

Мне отчасти нравится эта концепция, но если мне все равно придется построить таблицу, я просто сделаю автоматическое приращение и добавлю строки вручную, пока она не станет достаточно большой.

BCS 21.11.2008 01:04

Похоже, вы можете создавать достаточно большие наборы с помощью:

select 9 union all select 10 union all select 11 union all select 12 union all select 13 ...

Я получил переполнение стека парсера в 5300, на 5.0.51a.

Вау просто вау! вы на самом деле это тестировали ?! Ух ты!

BCS 21.11.2008 09:02

@BCS, введите это в адресную строку: data:text/html,<script>for(var x=1;x<=5678;++x)document.write((x===1?'':' union all ')+'select '+x);</script>

Pacerier 01.04.2015 16:04

@Pacerier Отличная техника, не только для этого приложения.

collapsar 08.02.2018 17:21

Вы можете попробовать что-то вроде этого:

SELECT @rn:=@rn+1 as n
FROM (select @rn:=2)t, `order` rows_1, `order` rows_2 --, rows_n as needed...
LIMIT 4

Где order - это просто пример некоторой таблицы с достаточно большим набором строк.

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

Я собираюсь разгадать этот вопрос, но он выглядит аккуратно!

BCS 01.01.2009 06:26

По сути, самый внутренний выбор инициализирует переменную сеанса до 2, затем внешний выбор увеличивает эту переменную для каждой строки, в этом случае декартово соединение с order означает, что переменная получит связь с последовательностью чисел от 2 до количества заказов + 2 (ограничение 4 ограничивает это до 4 чисел)

John Nilsson 01.01.2009 23:57

Это «решение», по-видимому, требует существующей таблицы order, содержащей полный список возможных совпадающих целых чисел. Я не могу получить ничего, кроме результата с одной строкой, если попытаюсь запустить, не присоединяясь к большой уже существующей таблице с действительными целыми числами, уже находящимися в ней.

rektide 03.04.2013 00:42

@rektide, не "появляется". Это является неверно и вообще не работает.

Pacerier 01.04.2015 15:38

О, это было очень давно. Я думаю, что моим намерением был «заказ», как в Заказе на поставку (в то время я занимался ERP-системами, и в такой системе можно было ожидать, что такая таблица будет достаточно большой). Но нет, я не думаю, что моим намерением было использовать реальные целые числа из этой таблицы. Я посмотрю, смогу ли я его немного улучшить.

John Nilsson 02.04.2015 17:29

Если бы вы использовали Oracle, вам бы подошли «конвейерные функции». К сожалению, в MySQL нет такой конструкции.

В зависимости от масштаба чисел, которые вы хотите набрать, я вижу два простых пути: вы либо заполняете временную таблицу только нужными вам числами (возможно, используя таблицы памяти, заполненные хранимой процедурой) для одного запроса, либо вверх front, вы строите большую таблицу, которая насчитывает от 1 до 1 000 000, и выбираете ее ограниченные области.

Предупреждение: если вы вставляете числа по одной строке за раз, вы в конечном итоге выполняете N команд, где N - количество строк, которые вам нужно вставить.

Вы можете уменьшить это число до O (log N), используя временную таблицу (см. Ниже, как вставить числа от 10000 до 10699):

mysql> CREATE TABLE `tmp_keys` (`k` INTEGER UNSIGNED, PRIMARY KEY (`k`));
Query OK, 0 rows affected (0.11 sec)

mysql> INSERT INTO `tmp_keys` VALUES (0),(1),(2),(3),(4),(5),(6),(7);
Query OK, 8 rows affected (0.03 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+8 from `tmp_keys`;
Query OK, 8 rows affected (0.02 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+16 from `tmp_keys`;
Query OK, 16 rows affected (0.03 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+32 from `tmp_keys`;
Query OK, 32 rows affected (0.03 sec)
Records: 32  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+64 from `tmp_keys`;
Query OK, 64 rows affected (0.03 sec)
Records: 64  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+128 from `tmp_keys`;
Query OK, 128 rows affected (0.05 sec)
Records: 128  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+256 from `tmp_keys`;
Query OK, 256 rows affected (0.03 sec)
Records: 256  Duplicates: 0  Warnings: 0

mysql> INSERT INTO `tmp_keys` SELECT k+512 from `tmp_keys`;
Query OK, 512 rows affected (0.11 sec)
Records: 512  Duplicates: 0  Warnings: 0

mysql> INSERT INTO inttable SELECT k+10000 FROM `tmp_keys` WHERE k<700;
Query OK, 700 rows affected (0.16 sec)
Records: 700  Duplicates: 0  Warnings: 0

edit: fyi, к сожалению, это не будет работать с истинным временная таблица с MySQL 5.0, поскольку оно не может вставляться в себя (вы можете перемещаться между двумя временными таблицами).

edit: вы можете использовать Механизм хранения ПАМЯТИ, чтобы предотвратить утечку в "реальной" базе данных. Интересно, разработал ли кто-нибудь механизм виртуального хранилища "NUMBERS" для создания экземпляра виртуального хранилища для создания подобных последовательностей. (увы, не переносится за пределы MySQL)

хорошее решение KISS. OTOH материализует все это; (. +1

BCS 01.01.2009 06:28

Да уж. Жаль, что нет числа SELECT FROM INTEGERS WHERE number> 0 AND number <10000 ... но технически я полагаю, что кто-то может придумать механизм виртуального хранения, который делает это.

Jason S 01.01.2009 19:14

хмммм ... кто-то получил этот ответ, по какой-то конкретной причине?

Jason S 19.03.2010 16:57

... и кому-то понадобилось 5 лет, чтобы понять, почему?

Jason S 01.04.2015 17:15

Я нашел это решение в сети

SET @row := 0;
SELECT @row := @row + 1 as row, t.*
FROM some_table t, (SELECT @row := 0) r

Единый запрос, быстрый и делает именно то, что я хотел: теперь я могу «пронумеровать» «выборки», найденные в сложном запросе, с уникальными номерами, начинающимися с 1 и увеличивающимися один раз для каждой строки в результате.

Я думаю, что это также сработает для проблемы, перечисленной выше: отрегулируйте начальное начальное значение для @row и добавьте пункт ограничения, чтобы установить максимум.

Кстати: я думаю, что буква «р» на самом деле не нужна.

ddsp

да необходим r - Ошибка 1248: каждая производная таблица должна иметь собственный псевдоним

Unreason 13.11.2010 00:25

Количество выбранных строк берется из some_table, а не r. Если some_table не имеет строк, вы ничего не получите. Я использовал это для создания набора тестовых данных, для которых нужны были только имена и пароли. Последовательность цифр превратилась в имена, а пароль был просто ШИФРОВАТЬ ('passwd'), так что все они были одинаковыми. Для создания строк я выбрал из другой таблицы, но на самом деле не выбрал ни один из столбцов. Он просто дал мне строку для каждой строки в some_table, все с последовательными номерами.

Mnebuerquo 01.04.2011 00:26

+ Многие, я немного в шоке - понятия не имел, что MySQL может это сделать. Эти два отдельных запроса работают, например, для изменения последовательности подмножества таблицы: SET @row := 0 и UPDATE foo SET position = (@row := @row + 1) WHERE <conditions> ORDER BY last_modified ASC.

Izkata 14.06.2012 00:39

Выполнение этого из C# дает ошибку: «Параметр '@row' должен быть определен». Но я нашел решение здесь: stackoverflow.com/questions/958953/…

EricP 21.06.2012 23:09

@Izkata, Дэвид, такое поведение гарантируется спецификациями? Насколько вам известно, будущая версия может дать нам одно и то же значение для всех строк и делать приращение только после всего выбора.

Pacerier 01.04.2015 11:30

Следующее вернет 1..10000 и не так медленно

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;

объяснение было бы неплохим - каждый t - t4 содержит 10 строк фиктивных данных, их декартово произведение равно 10 ^ 4, то есть 10000 строк фиктивных данных, а внешний выбор - это просто версия mysql для rownumber

Aprillion 21.06.2012 19:57

@Aprillion, 2 ^ 14 будет делать то же самое. Всего 28 значений вместо 40.

Pacerier 01.04.2015 15:28

Вы можете избавиться от объявления переменной, заменив «@row: = @row + 1 as row» на «concat (t.0, t2.0, t3.0, t4.0) + 1 as row», а затем отсортировав по "ряду". Чтобы получить точный результат, вам также необходимо изменить дублирующуюся строку «select 6» в каждом подзапросе на «select 2» («2» в настоящее время не используется, но «6» отображается дважды). В качестве бонуса вы также можете сократить каждое «объединение всех» до «объединение», поскольку больше не должно быть повторяющихся строк.

Seth McCauley 07.07.2016 00:20

@Seth McCauley: нет необходимости менять 6 на 2. значения даже не используются. с таким же успехом все могут быть нулевыми. только @row := @row + 1 as row необходим для получения увеличивающегося числа в строке. союзы просто умножаются, чтобы получить количество строк.

skb 12.10.2016 05:21

Сначала это не удалось с ошибкой «Каждая производная таблица должна иметь собственный псевдоним». Легко исправить, присвоив окончательному SELECT псевдоним - например, добавить t5 в самом конце.

Steve Chambers 20.05.2018 18:31

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

Предположим, вам нужен выбор с диапазоном всех значений BOOLEAN:

SELECT 0 as b UNION SELECT 1 as b;

мы можем сделать вид

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

тогда вы можете сделать Byte с помощью

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;

тогда вы можете сделать

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

тогда вы можете сделать

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

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

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

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

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

или же

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

вы могли бы ускорить это с помощью немного более быстрой функции MAKEDATE

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

Обратите внимание, что эти уловки ОЧЕНЬ МЕДЛЕННЫЕ и позволяют создавать только КОНЕЧНЫЕ последовательности в заранее определенном домене (например, int16 = 0 ... 65536)

Я уверен, что вы можете немного изменить запросы, чтобы ускорить процесс, указав MySQL, где прекратить вычисление;) (используя предложения ON вместо предложений WHERE и тому подобное)

Например:

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;

будет загружать ваш SQL-сервер на несколько часов

тем не мение

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);

будет работать достаточно быстро - даже если MAX-MIN огромен, пока вы ограничиваете результат LIMIT 1,30 или что-то в этом роде. COUNT (*), однако, займет много времени, и если вы сделаете ошибку, добавив ORDER BY, когда MAX-MIN больше, чем, скажем, 100k, для вычисления снова потребуется несколько секунд ...

Вот компактная двоичная версия метода, используемого в других ответах здесь:

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

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

В этой версии используется 8 «бит», поэтому она считается от 0 до 255, но вы можете легко это настроить.

Последовательность чисел от 1 до 100 000:

SELECT e*10000+d*1000+c*100+b*10+a n FROM
(select 0 a 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) t1,
(select 0 b 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 c 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 d 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 0 e 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) t5
order by 1

Я использую его для проверки, если какое-то число не в порядке, например:

select * from (
    select 121 id
    union all select 123
    union all select 125
    union all select 126
    union all select 127
    union all select 128
    union all select 129
) a
right join (
    SELECT e*10000+d*1000+c*100+b*10+a n FROM
    (select 0 a 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) t1,
    (select 0 b 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 c 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 d 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 0 e 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) t5
    order by 1
) seq on seq.n=a.id
where seq.n between 121 and 129
and   id is null

Результатом будет разрыв между числами 122 и 124 последовательности между 121 и 129:

id     n
----   ---
null   122
null   124

Может кому поможет!

Если вы используете Форк MySQL MySQL, двигатель SEQUENCE позволяет напрямую генерировать числовые последовательности. Это делается с помощью виртуальных (поддельных) таблиц с одним столбцом.

Например, чтобы сгенерировать последовательность целых чисел от 1 до 1000, сделайте следующее

     SELECT seq FROM seq_1_to_1000;

От 0 до 11 сделайте это.

     SELECT seq FROM seq_0_to_11;

Сделайте это для последовательных значений DATE за неделю, начиная с сегодняшнего дня.

SELECT FROM_DAYS(seq + TO_DAYS(CURDATE)) dateseq FROM seq_0_to_6

Сделайте это в течение десятилетия последовательных значений DATE, начинающихся с «2010-01-01».

SELECT FROM_DAYS(seq + TO_DAYS('2010-01-01')) dateseq
  FROM seq_0_to_3800
 WHERE FROM_DAYS(seq + TO_DAYS('2010-01-01')) < '2010-01-01' + INTERVAL 10 YEAR

Если вы не используете MariaDB, подумайте об этом.

Я пробовал вот это: sqlzoo.net/wiki/Guest_House_Assessment_Hard, и это не сработало. Однако весьма вероятно, что из-за того, что в браузере мы работаем с обернутой MariaDB, это не работает только по этой причине.

George Pligoropoulos 10.12.2017 01:47

Это потрясающее решение, которое позволяет вам думать о многом, например, рассчитывать прогнозируемый доход на основе повторяющегося графика, который выполняется с ежедневной, еженедельной, ежемесячной, ежегодной, двухнедельной и т. д. Частотой.

Calin 03.10.2019 22:42

Этот запрос генерирует числа от 0 до 1023. Я считаю, что он будет работать с любым типом базы данных sql:

select
     i0.i
    +i1.i*2
    +i2.i*4
    +i3.i*8
    +i4.i*16
    +i5.i*32
    +i6.i*64
    +i7.i*128
    +i8.i*256
    +i9.i*512
    as i
from
               (select 0 as i union select 1) as i0
    cross join (select 0 as i union select 1) as i1
    cross join (select 0 as i union select 1) as i2
    cross join (select 0 as i union select 1) as i3
    cross join (select 0 as i union select 1) as i4
    cross join (select 0 as i union select 1) as i5
    cross join (select 0 as i union select 1) as i6
    cross join (select 0 as i union select 1) as i7
    cross join (select 0 as i union select 1) as i8
    cross join (select 0 as i union select 1) as i9

Самый простой способ сделать это:

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

или в одном запросе:

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

Функция FLOOR() используется здесь, чтобы получить INTEGER вместо FLOAT. Иногда это необходимо.

Мой ответ был вдохновлен Дэвид Бедный ответ. Спасибо, Дэвид!

попробуйте это .. у меня это работает в mysql версии 8.0. вы можете изменить запрос ниже в соответствии с вашим требуемым диапазоном

WITH recursive numbers AS (
    select 0 as Date
   union all
   select Date + 1
   from numbers
   where Date < 10)
select * from numbers;

и да, без создания таблицы, как указано в вашем сообщении

Счетчик от 1 до 1000:

  • нет необходимости создавать стол
  • время выполнения ~ 0,0014 сек
  • можно преобразовать в представление
    select tt.row from
    (
    SELECT cast( concat(t.0,t2.0,t3.0) + 1 As UNSIGNED) as 'row' FROM 
    (select 0 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) t,
    (select 0 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) t2, 
    (select 0 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) t3
    ) tt
    order by tt.row

Кредиты: отвечать, комментарий Сета МакКоли под ответом.

Другие вопросы по теме