générer une séquence entière dans MySQL

j'ai besoin de faire une jointure avec une table/ensemble de résultats/quoi que ce soit qui a les entiers n à m inclusive. Y a-t-il un moyen trivial d'obtenir ça sans juste construire la table?

(BTW comment s'appellerait ce type de construction, une"Meta query"?)

m-n est limité à quelque chose de raisonnable (<1000's)

44
demandé sur BCS 2008-11-20 09:04:53

14 réponses

il n'y a pas de générateur de numéro de séquence ( CREATE SEQUENCE ) dans MySQL. La chose la plus proche est AUTO_INCREMENT , qui peut vous aider à construire la table.

5
répondu Eugene Yokota 2008-11-20 08:33:47

j'ai trouvé cette solution sur le web

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

requête simple, rapide, et fait exactement ce que je voulais: maintenant, je peux "numéroter" les "sélections" trouvées à partir d'une requête complexe avec des numéros uniques commençant à 1 et incrémentant une fois pour chaque ligne dans le résultat.

je pense que cela fonctionnera aussi pour la question mentionnée ci-dessus: ajuster la valeur initiale de @row et ajouter une clause limite pour fixer le maximum.

BTW: je pense que le "r" n'est pas vraiment nécessaire.

ddsp

90
répondu David Poor 2012-09-14 05:20:21

1..10000 et n'est pas si lent

SELECT @row := @row + 1 as row FROM 
(select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 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 3 union all select 4 union all select 5 union all select 6 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 3 union all select 4 union all select 5 union all select 6 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 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) t4, 
(SELECT @row:=0)
30
répondu Unreason 2010-04-16 10:04:04

si vous utilisez le fourche MariaDB de MySQL , le SEQUENCE moteur permet la génération directe de séquences de nombres. Il le fait en utilisant virtuel (faux) une colonne des tableaux.

par exemple, pour générer la séquence d'entiers de 1 à 1000, faites ceci

     SELECT seq FROM seq_1_to_1000;

pour 0 à 11, Faites ceci.

     SELECT seq FROM seq_0_to_11;

pour une semaine de DATE consécutive les valeurs à partir d'aujourd'hui, faire.

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

Pour une décennie d'consécutifs DATE valeurs commençant par '2010-01-01' faire.

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

si vous n 'utilisez pas MariaDB, veuillez l' envisager.

14
répondu O. Jones 2017-01-08 13:08:24

vous pourriez essayer quelque chose comme ceci:

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

order est juste un exemple d'une table avec un ensemble raisonnablement grand de lignes.

Edit: la réponse originale était fausse, et tout crédit devrait aller à David Poor qui a fourni un exemple de travail du même concept

5
répondu John Nilsson 2015-04-02 14:43:53

Il y a un moyen d'obtenir une plage de valeurs dans une seule requête, mais il est un peu lent. Il peut être accéléré en utilisant des tables de cache.

supposons que vous voulez un select avec une plage de toutes les valeurs booléennes:

SELECT 0 as b UNION SELECT 1 as b;

nous pouvons faire une vue

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

alors vous pouvez faire un Byte par

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;

, alors vous pouvez faire un

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

, alors vous pouvez faire un

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

pour accélérer cela j'ai sauté l'auto-calcul des valeurs de byte et fait moi-même un

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

si vous avez besoin d'une plage de dates, vous pouvez le faire.

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

ou

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

vous pourriez être en mesure d'accélérer cela avec la fonction MAKEDATE légèrement plus rapide

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

veuillez noter que ces astuces sont très lentes et ne permettent que la création de séquences finies dans un domaine prédéfini (par exemple int16 = 0...65536 )

je suis sûr que vous pouvez modifier les requêtes un peu pour accélérer les choses en suggérant à MySQL où arrêter de calculer ;) (en utilisant des clauses ON au lieu d'où des clauses et des trucs comme ça)

par exemple:

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;

va garder votre serveur SQL occupé pendant quelques heures

cependant

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

fonctionnera raisonnablement rapide-même si MAX-MIN est énorme tant que vous limitez le résultat avec limite 1,30 ou quelque chose. un comptage (*) prendra cependant des âges et si vous faites l'erreur d'ajouter de l'ordre lorsque MAX-MIN est plus grand que 100k, il vous faudra encore plusieurs secondes pour calculer...

3
répondu CorvusCorax 2011-02-02 10:38:45

Quelle est la taille de m?

Vous pourriez faire quelque chose comme:

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;

où l'augmentation automatique est définie à n et la clause where se compare à m et le nombre de fois que les deux tableaux sont répétés est au moins ceil(log(m-n+1)/log(2)).

(la table non-temporaire deux pourrait être omise en remplaçant deux par (select null foo union all select null) dans la table créer temporaire seq.)

2
répondu ysth 2008-11-20 09:42:47

séquence de nombres entre 1 et 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

Je l'utilise pour vérifier si un certain nombre est hors séquence, quelque chose comme ceci:

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

le résultat sera l'intervalle des numéros 122 et 124 de la séquence entre 121 et 129:

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

Peut-être que ça aide quelqu'un!

2
répondu lynx_74 2016-10-07 13:34:13

vous semblez être capable de construire des ensembles raisonnablement grands avec:

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

j'ai un débordement de pile d'analyseur dans les 5300, sur 5.0.51 A.

1
répondu ysth 2008-11-21 05:48:34

avertissement: si vous insérez des numéros une ligne à la fois, vous finirez par exécuter N commandes où N est le nombre de lignes que vous devez insérer.

vous pouvez obtenir ce o (log N) en utilisant une table temporaire (voir ci-dessous pour insérer des nombres de 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, malheureusement cela ne fonctionnera pas avec un vrai table temporaire avec MySQL 5.0 comme il ne peut pas s'insérer dans lui-même (vous pourriez rebondir et-vient entre les deux tables temporaires).

edit: vous pouvez utiliser un moteur de mémoire de mémoire pour empêcher cela d'être réellement un drain sur la base de données "réel". Je me demande si quelqu'un a développé un moteur de stockage virtuel "NUMBERS" pour instancier le stockage virtuel pour créer des séquences comme celle-ci. (hélas, hors MySQL)

1
répondu Jason S 2009-01-01 16:18:28

Voici une version binaire compacte de la technique utilisée dans d'autres réponses ici:

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

il n'y a pas de phase unique ou de tri, pas de conversion de chaîne en nombre, pas d'opérations arithmétiques, et chaque table factice n'a que 2 lignes, donc elle devrait être assez rapide.

Cette version utilise 8 bits "" donc, il compte de 0 à 255, mais vous pouvez facilement modifier.

1
répondu Tobia 2016-07-15 11:04:07

cette requête génère des nombres de 0 à 1023. Je crois que cela fonctionnerait dans n'importe quelle saveur de base de données 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
1
répondu George Polevoy 2017-03-01 14:33:01

la façon la plus simple de faire ceci est:

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

ou dans une requête:

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

la fonction FLOOR() est utilisée ici pour obtenir un INTEGER à la place d'un FLOAT . Parfois, il est nécessaire.

ma réponse a été inspirée par David Poor answer . Merci David!

1
répondu simhumileco 2018-07-19 16:59:33

si vous utilisiez Oracle, "fonctions pipelinées" serait la voie à suivre. Malheureusement, MySQL dispose pas d'une telle construction.

selon l'échelle des nombres que vous voulez ensembles de, je vois deux façons simples d'aller : vous peupler une table temporaire avec juste les nombres que vous avez besoin (peut-être en utilisant des tables de mémoire peuplées par une procédure stockée) pour une requête simple ou, à l'avance, vous construisez une grande table qui compte de 1 à 1.000.000 et sélectionnez les régions limitées de il.

0
répondu Sean McSomething 2008-12-30 18:32:45