Comment générer une séquence dans mysql

19

Considérez ce tableau dans mysql

create table numbers (number int);
insert into numbers values (3), (2), (9);
select * from numbers;

+--------+
| number |
+--------+
|      3 |
|      2 |
|      9 |
+--------+

Existe-t-il une requête simple pour générer une table avec les colonnes suivantes

  1. Les chiffres de 1 à 10
  2. 1 si le nombre est présent dans les numéros de table, et 0 sinon

Je suppose que vous devez créer une séquence de chiffres pour ce faire. Si possible, je veux créer une telle séquence sans la stocker dans la base de données.

Question connexe: existe-t-il une requête de sélection qui génère une séquence de nombres de 1 à 10 (ou 100 ou 1000)?

sjdh
la source

Réponses:

24

DANS MariaDB

MariaDB dispose d'un moteur de stockage SEQUENCE . Donc, si vous utilisez MariaDB, tous vos problèmes de séquence sont terminés (ou viennent de commencer).

Séquence de 10 chiffres

select * from seq_1_to_10;

NE PAS UTILISER DE TABLEAUX

Séquence de 10 chiffres

select * from
(select 0 x 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) A;

Séquence de 100 nombres

select (t*10+u+1) x from
(select 0 t 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) A,
(select 0 u 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) B
order by x;

Séquence de 1000 nombres

select (h*100+t*10+u+1) x from
(select 0 h 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) A,
(select 0 t 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) B,
(select 0 u 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) C
order by x;

Séquence de 10000 nombres

select (th*1000+h*100+t*10+u+1) x from
(select 0 th 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) A,
(select 0 h 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) B,
(select 0 t 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) C,
(select 0 u 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) D
order by x;

UTILISATION DES TABLES

Séquence de 10 chiffres

use test
drop table if exists seq10;
create table seq10
(x int not null auto_increment primary key);
insert into seq10 values (),(),(),(),(),(),(),(),(),();
select * from seq10;

Séquence de 100 nombres

use test
drop table if exists seq100;
create table seq100
(x int not null auto_increment primary key);
insert into seq100 values (),(),(),(),(),(),(),(),(),();
insert into seq100 values (),(),(),(),(),(),(),(),(),();
insert into seq100 values (),(),(),(),(),(),(),(),(),();
insert into seq100 values (),(),(),(),(),(),(),(),(),();
insert into seq100 values (),(),(),(),(),(),(),(),(),();
insert into seq100 select x + 50 from seq100;
select * from seq100;

Séquence de 1000 nombres

use test
drop table if exists seq1000;
create table seq1000
(x int not null auto_increment primary key);
insert into seq1000 values ();
set @p= -1;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
set @p=@p+1; insert into seq1000 select x+power(2,@p) from seq1000 where (x+power(2,@p)) <= 1000;
select * from seq1000;

Séquence de n'importe quel nombre (exemple: 3,5 millions)

use test
drop table if exists seq;
create table seq
(x int not null auto_increment primary key);
insert into seq values ();
set @maxseq = 3500000;
set @p = -1;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
set @p=@p+1; insert into seq select x+power(2,@p) from seq where (x+power(2,@p)) <= @maxseq;
select max(x),count(x) from seq;

VOTRE QUESTION RÉELLE

En utilisant la séquence 0..9, vous avez quitté rejoindre la séquence contre la table

select A.number,1-ISNULL(B.number) present from
(select 0 number 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) A
left join numbers B using (number);

Vos exemples de données avec la nouvelle requête

mysql> drop table numbers;
Query OK, 0 rows affected (0.01 sec)

mysql> drop table if exists numbers;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> create table numbers (number int);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into numbers values (3), (2), (9);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select A.number,1-ISNULL(B.number) present from
    -> (select 0 number 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) A
    -> left join numbers B using (number);
+--------+---------+
| number | present |
+--------+---------+
|      0 |       0 |
|      1 |       0 |
|      2 |       1 |
|      3 |       1 |
|      4 |       0 |
|      5 |       0 |
|      6 |       0 |
|      7 |       0 |
|      8 |       0 |
|      9 |       1 |
+--------+---------+
10 rows in set (0.00 sec)

mysql>

ESSAIE !!!

RolandoMySQLDBA
la source
ne serait-il pas beaucoup plus simple d'utiliser une fonction ici? Une fonction personnalisée qui renvoie une plage comme MariaDB comme vous l'avez mentionné,range(10,20)
azerafati
2
@Rolando - est-ce toujours la meilleure façon de procéder? Demander un ami.
Max Vernon
1
@MaxVernon En dehors de MariaDB, ce sont à peu près la façon dont je fais des séquences sans utiliser de fonctions. Ne pas utiliser de tables évite d'avoir à créer des E / S disque pour effectuer des séquences.
RolandoMySQLDBA
@MaxVernon Avec la nouvelle version GA de MySQL 8.0 (et la version MariaDB 10.2 GA, sortie il y a un an), vous pouvez utiliser des CTE récursifs qui rendent cela plus simple. Eh bien, le moteur de stockage de séquences MariaDB est le plus simple, mais les CTE récursifs pourraient être la voie à suivre avec MySQL et les requêtes qui doivent fonctionner à la fois sur MySQL et MariaDB.
dbdemon
5

Avec MySQL 8.0, MariaDB 10.2 et les versions ultérieures, vous pouvez utiliser des CTE récursifs, donc:

WITH RECURSIVE nums AS (
    SELECT 1 AS value
    UNION ALL
    SELECT value + 1 AS value
    FROM nums
    WHERE nums.value <= 9
)
SELECT *
FROM nums;

Vous pouvez évidemment le modifier pour utiliser la valeur de début, l'étape et la valeur de fin de votre choix.

Quant à la deuxième question, il est alors trivial d'élargir ce qui précède (en s'inspirant d'une partie de la réponse de Ronaldo):

WITH RECURSIVE nums AS (
    SELECT 1 AS value
    UNION ALL
    SELECT value + 1 AS value
    FROM nums
    WHERE nums.value <= 9
)
SELECT nums.value, 1-ISNULL(numbers.number) present
FROM nums
  LEFT JOIN numbers ON numbers.number = nums.value
ORDER BY nums.value;

Éditer:

MariaDB 10.3 a introduit des objets de séquence (tels que définis dans le standard SQL et comme vu par exemple dans le SGBDR Oracle). Ceux-ci ne sont pas utiles pour cette question particulière car les valeurs sont stockées dans la base de données, mais la fonctionnalité pourrait être utile dans d'autres cas d'utilisation liés à la séquence.

dbdemon
la source