2010-05-17 3 views
35

Używając tabeli DUAL, jak mogę uzyskać listę liczb od 1 do 100?SQL do generowania listy liczb od 1 do 100

+0

Czy to zadanie domowe? Jeśli nie, uwzględniony wymóg "używania tabeli DUAL" wydaje mi się arbitralny i dziwny. – bart

+4

@bart - używanie DUAL jako źródła jest dobrze znanym rozwiązaniem problemu generowania wierszy, więc jego włączenie do pytania nie jest ani arbitralne, ani dziwne. – APC

+0

byłoby interesujące wiedzieć, dlaczego chcesz to zrobić. – Randy

Odpowiedz

53

Twoje pytanie jest trudne do zrozumienia, ale jeśli chcesz, aby wybrać numery od 1 do 100, to powinno załatwić sprawę:

Select Rownum r 
From dual 
Connect By Rownum <= 100 
6

odpowiedź Piotra jest moim ulubionym, zbyt.

Jeśli szukasz więcej szczegółów, istnieje niezły przegląd, IMO, here. Szczególnie interesujące jest odczytanie benchmarks.

+0

Dzięki - twój pierwszy link był bardzo przydatny. – Juffy

19

Innym ciekawym rozwiązaniem w Oracle PL/SQL:

SELECT LEVEL n 
     FROM DUAL 
CONNECT BY LEVEL <= 100; 
+7

To jest zwykły Oracle SQL. Działa dobrze poza kontekstem PL/SQL. –

12

zrobić to w przykry sposób. Użyj niesamowite MODEL klauzuli:

SELECT V 
FROM DUAL 
MODEL DIMENSION BY (0 R) 
     MEASURES (0 V) 
     RULES ITERATE (100) (
     V[ITERATION_NUMBER] = ITERATION_NUMBER + 1 
    ) 
ORDER BY 1 

Dowód: http://sqlfiddle.com/#!4/d41d8/20837

+2

To proste, dlaczego nie pasuje do wzoru ... :-) – igr

+2

@igr: Rzucam Ci wyzwanie, abyś faktycznie udzielił tej odpowiedzi :-) –

+0

co to jest "CV (R)"? Czy to jest jak aktualna wartość? czy coś? – zygimantus

0

Wariant przykładu Piotra, który pokazuje sposób ten może być wykorzystywany do generowania wszystkie liczby z zakresu od 0 do 99.

with digits as (
    select mod(rownum,10) as num 
    from dual 
    connect by rownum <= 10 
) 
select a.num*10+b.num as num 
from digits a 
     ,digits b 
order by num 
; 

Coś takiego przydaje się, gdy wykonujesz przypisanie identyfikatorów partii i szukasz przedmiotów, które nie zostały jeszcze przypisane.

Na przykład, jeśli sprzedajesz bilety do gry w bingo, możesz chcieć przydzielić partie 100 pracowników piętra (zgadnij, w jaki sposób użyłem do finansowania podwyżki na sport). Gdy sprzedają partię, otrzymują kolejną partię w sekwencji. Jednak osoby kupujące bilety mogą wybrać zakup biletów z partii. Można zadać pytanie: "jakie bilety zostały sprzedane".

W tym przypadku mamy tylko częściową, losową, listę biletów, które zostały zwrócone w ramach danej partii i wymagają pełnej listy wszystkich możliwości ustalenia, których nie mamy.

with range as (
    select mod(rownum,100) as num 
    from dual 
    connect by rownum <= 100 
), 
AllPossible as (
    select a.num*100+b.num as TicketNum 
    from batches a 
     ,range b 
    order by num 
) 
select TicketNum as TicketsSold 
from AllPossible 
where AllPossible.Ticket not in (select TicketNum from TicketsReturned) 
; 

Przepraszam za użycie słów kluczowych, zmieniłem niektóre nazwy zmiennych z przykładu z prawdziwego świata.

... Aby wykazać, dlaczego coś takiego byłoby przydatne

-1
SELECT * FROM `DUAL` WHERE id>0 AND id<101 

Powyższe zapytanie jest napisane w SQL w bazie danych.

+0

Do której bazy danych to służy? –

5

Jeśli chcesz, aby liczby całkowite były powiązane między dwiema liczbami całkowitymi (np.zacząć od czegoś innego niż 1), można użyć mniej więcej tak:

with bnd as (select 4 lo, 9 hi from dual) 
select (select lo from bnd) - 1 + level r 
from dual 
connect by level <= (select hi-lo from bnd); 

Daje:

4 
5 
6 
7 
8 
0

stworzyłem funkcję Oracle, która zwraca tablicę liczb

CREATE OR REPLACE FUNCTION [schema].FN_TABLE_NUMBERS(
    NUMINI INTEGER, 
    NUMFIN INTEGER, 
    EXPONENCIAL INTEGER DEFAULT 0 
) RETURN TBL_NUMBERS 
IS 
    NUMEROS TBL_NUMBERS; 
    INDICE NUMBER; 
BEGIN 
    NUMEROS := TBL_NUMBERS(); 

    FOR I IN (
     WITH TABLA AS (SELECT NUMINI, NUMFIN FROM DUAL) 
     SELECT NUMINI NUM FROM TABLA UNION ALL 
     SELECT 
      (SELECT NUMINI FROM TABLA) + (LEVEL*TO_NUMBER('1E'||TO_CHAR(EXPONENCIAL))) NUM 
     FROM DUAL 
     CONNECT BY 
      (LEVEL*TO_NUMBER('1E'||TO_CHAR(EXPONENCIAL))) <= (SELECT NUMFIN-NUMINI FROM TABLA) 
    ) LOOP 
     NUMEROS.EXTEND; 
     INDICE := NUMEROS.COUNT; 
     NUMEROS(INDICE):= i.NUM; 
    END LOOP; 

    RETURN NUMEROS; 

EXCEPTION 
    WHEN NO_DATA_FOUND THEN 
     RETURN NUMEROS; 
    WHEN OTHERS THEN 
     RETURN NUMEROS; 
END; 
/

Konieczne jest utworzenie nowego typu danych:

CREATE OR REPLACE TYPE [schema]."TBL_NUMBERS" IS TABLE OF NUMBER; 
/

Zastosowanie:

SELECT COLUMN_VALUE NUM FROM TABLE([schema].FN_TABLE_NUMBERS(1,10))--integers difference: 1;2;.......;10 

A jeśli potrzebujesz dziesiętnych pomiędzy liczbami autorem exponencial notacji:

SELECT COLUMN_VALUE NUM FROM TABLE([schema].FN_TABLE_NUMBERS(1,10,-1));--with 0.1 difference: 1;1.1;1.2;.......;10 
SELECT COLUMN_VALUE NUM FROM TABLE([schema].FN_TABLE_NUMBERS(1,10,-2));--with 0.01 difference: 1;1.01;1.02;.......;10 
2

Korzystanie GROUP BY CUBE:

SELECT ROWNUM 
FROM (SELECT 1 AS c FROM dual GROUP BY CUBE(1,1,1,1,1,1,1)) sub 
WHERE ROWNUM <=100; 

Rextester Demo

-1

nr n Potrzeba, aby dostać wszystko mądry dla measly 100 numerów, po prostu brute force go;)

select 1 from dual union 
select 2 from dual union 
select 3 from dual union 
select 4 from dual union 
select 5 from dual union 
select 6 from dual union 
select 7 from dual union 
select 8 from dual union 
select 9 from dual union 
select 10 from dual union 
select 11 from dual union 
select 12 from dual union 
select 13 from dual union 
select 14 from dual union 
select 15 from dual union 
select 16 from dual union 
select 17 from dual union 
select 18 from dual union 
select 19 from dual union 
select 20 from dual union 
select 21 from dual union 
select 22 from dual union 
select 23 from dual union 
select 24 from dual union 
select 25 from dual union 
select 26 from dual union 
select 27 from dual union 
select 28 from dual union 
select 29 from dual union 
select 30 from dual union 
select 31 from dual union 
select 32 from dual union 
select 33 from dual union 
select 34 from dual union 
select 35 from dual union 
select 36 from dual union 
select 37 from dual union 
select 38 from dual union 
select 39 from dual union 
select 40 from dual union 
select 41 from dual union 
select 42 from dual union 
select 43 from dual union 
select 44 from dual union 
select 45 from dual union 
select 46 from dual union 
select 47 from dual union 
select 48 from dual union 
select 49 from dual union 
select 50 from dual union 
select 51 from dual union 
select 52 from dual union 
select 53 from dual union 
select 54 from dual union 
select 55 from dual union 
select 56 from dual union 
select 57 from dual union 
select 58 from dual union 
select 59 from dual union 
select 60 from dual union 
select 61 from dual union 
select 62 from dual union 
select 63 from dual union 
select 64 from dual union 
select 65 from dual union 
select 66 from dual union 
select 67 from dual union 
select 68 from dual union 
select 69 from dual union 
select 70 from dual union 
select 71 from dual union 
select 72 from dual union 
select 73 from dual union 
select 74 from dual union 
select 75 from dual union 
select 76 from dual union 
select 77 from dual union 
select 78 from dual union 
select 79 from dual union 
select 80 from dual union 
select 81 from dual union 
select 82 from dual union 
select 83 from dual union 
select 84 from dual union 
select 85 from dual union 
select 86 from dual union 
select 87 from dual union 
select 88 from dual union 
select 89 from dual union 
select 90 from dual union 
select 91 from dual union 
select 92 from dual union 
select 93 from dual union 
select 94 from dual union 
select 95 from dual union 
select 96 from dual union 
select 97 from dual union 
select 98 from dual union 
select 99 from dual union 
select 100 from dual; 
0

Oto świetny sposób, aby wygenerować tabelę numeryczny. Nie używa tabeli DUAL, ale jeśli tabela DUAL kiedykolwiek zniknie, może to być plan zapasowy.

DECLARE @TotalNumbers INT = 100; 

DECLARE @From DATETIME = CONVERT(DATETIME, CONVERT(DATE, GETDATE())), 
     @To DATETIME = DATEADD(SECOND, @TotalNumbers - 1, CONVERT(DATETIME, CONVERT(DATE, GETDATE()))); 

WITH AlmostNumberTable (Hola) 
AS (SELECT @From 
    UNION ALL 
    SELECT DATEADD(SECOND, 1, Hola) 
    FROM AlmostNumberTable 
    WHERE Hola< @To 
    ) 
SELECT [Number] 
FROM 
(
    SELECT DATEPART(MINUTE, AlmostNumberTable.Hola) * 60 + DATEPART(SECOND, AlmostNumberTable.Hola) + 1 AS [Number] 
    FROM AlmostNumberTable 
) AS NumberTable; 

To chyba bzdura, ale to działające rozwiązanie i fajnie było pisać.