2009-09-25 4 views
12

Je dois obtenir un ensemble de résultats contenant les N premiers entiers positifs. Est-il possible d'utiliser uniquement une instruction SQL SELECT standard pour les obtenir (sans table de comptage fournie)?SQL SELECT pour obtenir les N premiers entiers positifs

Si ce n'est pas possible, y a-t-il un moyen spécifique de MySQL pour y parvenir?

+0

D'abord dans quelle définition? –

Répondre

15

Il semble que ce que vous voulez est un dummy rowset. En MySQL, il est impossible de disposer d'une table.

La plupart des grands systèmes offrent une façon de le faire:

  • En Oracle:

    SELECT level 
    FROM dual 
    CONNECT BY 
         level <= 10 
    
  • En SQL Server:

    WITH q AS 
         (
         SELECT 1 AS num 
         UNION ALL 
         SELECT num + 1 
         FROM q 
         WHERE num < 10 
         ) 
    SELECT * 
    FROM q 
    
  • En PostgreSQL:

    SELECT num 
    FROM generate_series(1, 10) num 
    

MySQL manque quelque chose comme ceci et cela est un grave inconvénient.

J'ai écrit un script simple pour générer des données de test pour les tables d'échantillons dans mon blog, ce sera peut-être utile:

CREATE TABLE filler (
     id INT NOT NULL PRIMARY KEY AUTO_INCREMENT 
) ENGINE=Memory; 

CREATE PROCEDURE prc_filler(cnt INT) 
BEGIN 
     DECLARE _cnt INT; 
     SET _cnt = 1; 
     WHILE _cnt <= cnt DO 
       INSERT 
       INTO filler 
       SELECT _cnt; 
       SET _cnt = _cnt + 1; 
     END WHILE; 
END 
$$ 

Vous appelez la procédure et la table est rempli avec les chiffres.

Vous pouvez le réutiliser pendant la durée de la session.

+0

Bonne réponse. C'est sûr que c'est utile. – monn

2

En supposant que vous voulez dire les récupérer d'une table, ici N est 10, en supposant que intcolumn est la colonne avec des nombres dedans.

SELECT intcolumn FROM numbers WHERE intcolumn > 0 LIMIT 10 

Modifier: Au cas où vous actuellement à la recherche pour obtenir l'ensemble mathématique des nombres positifs sans table, je réexaminerait, il peut être intensive (en fonction de la mise en œuvre). La pratique généralement acceptée semble être de créer une table de recherche complète de nombres, puis d'utiliser la requête ci-dessus.

+0

il suffit de changer> = à> pour obtenir seulement des positifs. – dusoft

+0

Est-ce que 0 est considéré comme positif ou négatif? – rahul

+0

Je viens de vérifier, apparemment la définition des nombres positifs est supérieure à 0. Apparemment zéro n'est ni (selon wikipedia). – Kazar

0

Jetez un oeil à la la followhing SO questions:

Edit:

Une autre aproche est de créer une procédure stockée qui fait que pour toi. PostgreSQL contient une fonction generate_series (start, stop) qui fait ce que vous voulez.

select * from generate_series(2,4); 
generate_series 
----------------- 
       2 
       3 
       4 
(3 rows) 

Je ne suis pas familier avec MySQL mais somthing comme ça devrait être facile à mettre en œuvre, si vous êtes d'accord avec SPs. This site montre une implémentation.

+0

Il semblerait que ces deux méthodes requièrent une table de recherche de quelque forme (en utilisant AUTO_INCREMENT) – Kazar

0

Je suis assez sûr que vous ne pouvez pas le faire, si je comprends bien votre question. Comme je comprends votre question, vous voulez la liste, à partir d'une seule instruction SQL, sans avoir à référencer une table spécifique?

Je suis assez sûr que ce n'est pas possible dans n'importe quel dialecte SQL. Si vous deviez obtenir un nombre incrémenté séquentiellement avec les résultats d'une autre requête, alors cela serait possible (selon le dialecte SQL, sur mssql, ce serait rownumber(), mais je ne sais pas comment dans MySql, mais c'est probablement là)

Mais ce n'est pas ce que je vous entends demander?

+0

Dans PostgreSQL, il existe une fonction appelée generate_series (start, stop) qui fait exactement ce que l'OP veut. –

1

Cela peut aider à

Pour obtenir un nombre aléatoire R dans la gamme i < = R < j, utiliser le PLANCHER d'expression (i + RAND() * (j - i)). Par exemple, pour obtenir un nombre entier aléatoire dans la plage comprise entre 7 < = R < 12, vous pouvez utiliser la déclaration suivante:

SELECT FLOOR(7 + (RAND() * 5));

+0

Il pose des questions sur les entiers positifs séquentiels. Pas à propos de hasard. –

4

solution bizarre, mais ...

SELECT 1 UNION SELECT 2 UNION SELECT 3.... 
2

La séquence que je propose permet au programmeur d'exécuter la requête suivante:

select value from sequence where value>=15 and value<100; 

Et pour obtenir les résultats attendus: la séquence des entiers compris entre 15 (inclus) et 100 (exclusif).

Si c'est ce que vous voulez, vous aurez à créer les deux vues suivantes, vues que vous déclarez une seule fois:

create view digits as select 0 n 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; 

create view sequence as select u.n+t.n*10+h.n*100 as value from digits as u cross join digits as t cross join digits as h; 

De cette façon, vous avez votre séquence avec une interface intuitive SELECT ...

Espérons que ça aide.

+0

Fou! ...et il fonctionne. J'avais besoin de quelque chose qui fonctionnait dans une vue - l'utilisation de l'assignation dans une variable est bloquée pour les vues. Agréable. –

9

Une solution possible (certes pas très élégante) est d'utiliser n'importe quelle table avec un nombre suffisant d'enregistrements.

Pour les 10 premiers entiers (en utilisant le mysql.help_relation, mais une table ferait), vous pouvez utiliser la requête suivante:

SELECT @N := @N +1 AS integers 
FROM mysql.help_relation , (SELECT @N:=0) dum LIMIT 10; 

Cela pourrait aussi être placé dans une fonction prise Min et Max.

+1

Merci pour le conseil. a utilisé avec succès les éléments suivants pour obtenir une plage de dates: SELECT @i: = DATE_SUB (@i, INTERVAL 1 DAY) date FROM mysql.help_relation, (SELECT @i: = CURRENT_DATE) v WHERE @i> DATE_SUB (CURRENT_DATE, INTERVALLE 3 MOIS); –

+0

Ceci n'est pas une solution générique. Cela fonctionne, à condition que la table utilisée ait au moins le nombre de lignes que vous voulez obtenir. Créer une table fictive sans lignes et SELECT @N: = @ N + 1 AS entiers FROM dummy, (SELECT @N: = 0) dum LIMIT 10 ne génère aucune ligne. – user1645975

+0

Peut-être vieux, mais c'est génial. Je savais que quelque chose comme ça devait exister. – slicedtoad

1

Si vous savez que N est limité (et le plus souvent il est), vous pouvez utiliser une construction comme:

select (a.digit + (10 * b.digit) + (100 * c.digit) + (1000 * d.digit) + (10000 * e.digit) + (100000 * f.digit)) as n 
    from (select 0 as digit 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) as a 
    cross join (select 0 as digit 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) as b 
    cross join (select 0 as digit 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) as c 
    cross join (select 0 as digit 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) as d 
    cross join (select 0 as digit 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) as e 
    cross join (select 0 as digit 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) as f; 

qui va générer les premiers millions de numéros. Si vous n'avez besoin que des nombres positifs, ajoutez simplement + 1 à l'expression.

Notez que dans MySQL en particulier, les résultats ne peuvent pas être triés.Vous devez ajouter order by n à la fin si vous avez besoin de numéros ordonnés. Cela augmentera considérablement le temps d'exécution (sur ma machine, il a grimpé de 5 ms à 500 ms).

Pour les requêtes simples, voici une requête pour seulement les 10000 premiers chiffres:

select (a.digit + (10 * b.digit) + (100 * c.digit) + (1000 * d.digit)) as n 
    from (select 0 as digit 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) as a 
    cross join (select 0 as digit 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) as b 
    cross join (select 0 as digit 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) as c 
    cross join (select 0 as digit 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) as d; 

Cette réponse est adaptée de la requête suivante qui retourne une plage de dates: https://stackoverflow.com/a/2157776/2948

0

Si votre base de données prend en charge fenêtrage analytique fonctionne ce qui suit est très simple fonctionne très bien:

SELECT row_number() over (partition by 1 order by 1) numbers 
FROM SOME_TABLE 
LIMIT 2700; 

Cette déclaration renvoie un ensemble de nombres de 1 à 2700.

Questions connexes