web-dev-qa-db-fra.com

ORACLE SQL: Obtenir tous les entiers entre deux nombres

Est-il possible de sélectionner les nombres (nombres entiers) inclus entre deux nombres avec SQL dans Oracle? Je ne veux pas créer de procédure ou de fonction PL/SQL. 

Par exemple, je dois obtenir les nombres entre 3 et 10. Le résultat sera les valeurs 3,4,5,6,7,8,9,10. 

THX. 

20
George

Cette astuce avec la table DUAL d’Oracle fonctionne également:

SQL> select n from
  2  ( select rownum n from dual connect by level <= 10)
  3  where n >= 3;

         N
----------
         3
         4
         5
         6
         7
         8
         9
        10
51
Tony Andrews

La première chose que je fais lorsque je crée une nouvelle base de données consiste à créer et à remplir des tables de base.

L'un est une liste de tous les entiers compris entre -N et N, un autre est une liste des dates 5 à 10 ans dans le futur (un travail planifié peut continuer de les créer si nécessaire, à l'avenir) et le dernier est une liste. de toutes les heures de la journée. Par exemple, les inetgers:

create table numbers (n integer primary key);
insert into numbers values (0);
insert into numbers select n+1 from numbers; commit;
insert into numbers select n+2 from numbers; commit;
insert into numbers select n+4 from numbers; commit;
insert into numbers select n+8 from numbers; commit;
insert into numbers select n+16 from numbers; commit;
insert into numbers select n+32 from numbers; commit;
insert into numbers select n+64 from numbers; commit;
insert into numbers select n+128 from numbers; commit;
insert into numbers select n+256 from numbers; commit;
insert into numbers select n+512 from numbers; commit;
insert into numbers select n+1024 from numbers; commit;
insert into numbers select n+2048 from numbers; commit;
insert into numbers select n+4096 from numbers; commit;
insert into numbers select n+8192 from numbers; commit;
insert into numbers select -n from numbers where n > 0; commit;

Ceci concerne DB2/z qui a le démarrage automatique de la transaction, raison pour laquelle il semble avoir des commits nus.

Oui, cela prend un espace (minimal) mais cela rend les requêtes beaucoup plus faciles à écrire, simplement en sélectionnant des valeurs dans ces tables. Il est également très portable dans presque tous les n'importe quel SGBD basé sur SQL.

Votre requête particulière serait alors simple:

select n from numbers where n >=3 and n <= 10;

Les chiffres des heures et les plages de dates sont très utiles pour le type d'applications de création de rapports sur lequel nous travaillons. Cela nous permet de ne créer aucune entrée pour les heures du jour (ou les dates) qui ne contiennent pas de données réelles. Ainsi, au lieu de (lorsqu'il n'y a pas de données le deuxième jour du mois):

Date       | Quantity
-----------+---------
2009-01-01 |        7
2009-01-03 |       27
2009-01-04 |        6

nous pouvons plutôt obtenir:

Date       | Quantity
-----------+---------
2009-01-01 |        7
2009-01-02 |        0
2009-01-03 |       27
2009-01-04 |        6
5
paxdiablo

Vous pouvez utiliser la clause MODEL pour cela.

SELECT c1 from dual
  MODEL DIMENSION BY (1 as rn)  MEASURES (1 as c1)
  RULES ITERATE (7)
  (c1[ITERATION_NUMBER]=ITERATION_NUMBER+7)
4
Gary Myers
SQL> var N_BEGIN number
SQL> var N_END number
SQL> exec :N_BEGIN := 3; :N_END := 10

PL/SQL procedure successfully completed.

SQL>  select :N_BEGIN + level - 1 n
  2     from dual
  3  connect by level <= :N_END - :N_BEGIN + 1
  4  /

         N
----------
         3
         4
         5
         6
         7
         8
         9
        10

8 rows selected.

Cela utilise le même truc que Tony. Notez que lorsque vous utilisez SQL * Plus 9, vous devez transformer cette requête en vue intégrée, comme l’a montré Tony. Dans SQL * Plus 10 ou supérieur, ce qui précède est suffisant.

Cordialement, .__ Rob.

4
Rob van Wijk

cette requête d'une seule ligne vous aidera,

select level lvl from dual where level<:upperbound and 

                              level >:lowerbound connect by level<:limt

Pour votre cas:

select level lvl from dual where level<10 and level >3 connect by level<11

laissez-moi savoir si des éclaircissements.

2
Thiyagu ATR

Ou vous pouvez utiliser Entre

Select Column1 from dummy_table where Column2 Between 3 and 10
1
Amit

Une façon de générer des nombres à partir d'une plage consiste à utiliser XMLTABLE('start to end'):

SELECT column_value
FROM XMLTABLE('3 to 10');

DBFiddle Demo

1
Lukasz Szozda

C'est un ajout tardif. Mais la solution semble être plus élégante et plus facile à utiliser.

Il utilise une fonction pipelined qui doit être installée une fois:

CREATE TYPE number_row_type AS OBJECT 
(
  num NUMBER
);

CREATE TYPE number_set_type AS TABLE OF number_row_type;

CREATE OR REPLACE FUNCTION number_range(p_start IN PLS_INTEGER, p_end IN PLS_INTEGER)
    RETURN number_set_type
    PIPELINED
IS
    out_rec number_row_type := number_row_type(NULL);

BEGIN
  FOR i IN p_start .. p_end LOOP
    out_rec.num := i;
    pipe row(out_rec);
  END LOOP;

END number_range;
/

Ensuite, vous pouvez l'utiliser comme ceci:

select * from table(number_range(1, 10));

NUM
---
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10

La solution est spécifique à Oracle.

1
Codo

Gary, pour montrer le résultat qu'il a expliqué, la requête modèle sera:

CHOISISSEZ c1 DANS DOUBLE MODÈLE DIMENSION DE (1 comme rn)
MESURES (1 comme c1) RÈGLES ITERATE (8) (C1 [NOMBRE ITERATION] = NOMBRE ITERATION + 3).

;) 

J'utilise toujours: 

SELECT (LEVEL - 1) + 3 comme résultat FROM Dual CONNECT BY Level <= 8

Où 3 est le numéro de départ et 8 le nombre "d'itérations". 

1
anthian

Je viens de faire une fonction table évaluée à faire cela dans le serveur SQL, si quelqu'un est intéressé, cela fonctionne parfaitement.

CREATE FUNCTION [dbo].[NumbersBetween]
(
    @StartN int,
    @EndN int
)
RETURNS 
@NumberList table
(
    Number int
)

AS

BEGIN

WHILE @StartN <= @EndN
    BEGIN
    insert into @NumberList
    VALUES (@StartN)
    set @StartN = @StartN + 1
    END

Return

END
GO

Si vous exécutez la requête: "select * from dbo.NumbersBetween (1,5)" (sans les guillemets bien sûr), le résultat sera

Number
-------
1
2
3
4
5
0
Gaspa79

Je veux partager une requête utile qui convertit une chaîne de virgules et une liste de nombres séparés par «-» en une liste de nombres développée équivalente

Un exemple qui convertit '1,2,3,50-60' en 

 1 
 2 
 3 
 50 
 51 
...
 60 
select distinct * from (SELECT (LEVEL - 1) + mini as result FROM (select REGEXP_SUBSTR (value, '[^-]+', 1, 1)mini ,nvl(REGEXP_SUBSTR (value, '[^-]+', 1, 2),0) maxi from (select REGEXP_SUBSTR (value, '[^,]+', 1, level) as value from (select '1,2,3,50-60' value from dual) connect by level <= length(regexp_replace(value,'[^,]*'))+1)) CONNECT BY Level <= (maxi-mini+1)) order by 1 asc;

Vous pouvez l'utiliser comme une vue et paramétrer la chaîne '1,2,3,50-60'

0
antoniolvsa
create table numbers (value number);

declare
    x number;
begin
    for x in 7 .. 25
    loop
        insert into numbers values (x);
    end loop;
end;
/
0
diaphol