2009-12-29 14 views
12

Chcę napisać zapytanie SQL, które akceptuje zmienną powiązania (np. NUM), a jego wynik składa się z jednej kolumny &: NUM liczba wierszy, każdy wiersz ma swój numer wiersza. to znaczy jeśli mijamy: NUM jako 7, wyjście powinno być:Zapytanie SQL o zwracanie N wierszy od podwójnego

VAL 
==== 
1 
2 
3 
4 
5 
6 
7 

Nie powinno być żadnych rzeczywiste tabele bazy danych w zapytaniu i nie kod PL/SQL powinien być stosowany. to znaczy, że tylko podwójne powinno być użyte w zapytaniu

Czy istnieje sposób na osiągnięcie tego?

+0

retagged jako wyrocznia, mam nadzieję, że to było poprawne –

+0

@Rob: Postgres obsługuje również PLSQL, ale nie obsługuje 'FROM DUAL', więc Oracle jest poprawne. –

+0

Dzięki Rob, poprawne to pytanie dotyczyło tylko bazy danych Oracle DB – Harish

Odpowiedz

33

Można użyć:

WHERE ROWNUM <= :NUM 

... ale tabela musi zawierać wiersz równy lub większy do granicy w zmiennej wiązania . This link demonstrates various row number generation techniques in Oracle.

Stosując CONNECT BY Oracle 10g +:

SELECT LEVEL 
    FROM DUAL 
CONNECT BY LEVEL <= :NUM 

Potwierdzone monojohnny że zmienna wiążą mogą być użyte. Próby uruchomienia na Oracle 9i, choć składnia CONNECT BY jest obsługiwana, powoduje błąd ORA-01436.

Jedyne, czego nie jestem w 100%, to jeśli CONNECT BY zaakceptuje limit ze zmiennej wiążącej.

referencyjny:

+0

+1 Ta metoda jest również sugerowana tutaj: http://www.adp-gmbh.ch/ora/sql/examples/generate_rows.html –

+0

Daje mi to błąd dla dowolnej wartości powyżej jednej. 'WYBIERZ POZIOM Z PODWÓJNEGO POŁĄCZENIA POZIOMU ​​<= 20': ORA-01436 – Kobi

+1

@Kobi: Jaka wersja - to działa dla mnie na 10g –

5

spróbować czegoś jak:

SELECT 1 AS Val FROM dual 
UNION ALL SELECT 2 FROM dual 
UNION ALL SELECT 3 FROM dual 
UNION ALL SELECT 4 FROM dual 
UNION ALL SELECT 5 FROM dual 
UNION ALL SELECT 6 FROM dual 
UNION ALL SELECT 7 FROM dual; 

Jest brudny, ale będzie to rade.

Zmieniano: Ach - trzeba przekazać w zmiennej poinformować, jak wysoko się udać ...

Tak jak o czymś takim:

SELECT t1.Val + t2.Val * 2 + t3.Val * 4 + t4.Val * 8 AS Val 
FROM 
(
SELECT 0 AS Val FROM dual 
UNION ALL SELECT 1 FROM dual 
) AS t1, 
(
SELECT 0 AS Val FROM dual 
UNION ALL SELECT 1 FROM dual 
) AS t2, 
(
SELECT 0 AS Val FROM dual 
UNION ALL SELECT 1 FROM dual 
) AS t3, 
(
SELECT 0 AS Val FROM dual 
UNION ALL SELECT 1 FROM dual 
) AS t4 
WHERE t1.Val + t2.Val * 2 + t3.Val * 4 + t4.Val * 8 <= 7; 

Ok ... edycji ponownie, teraz przy użyciu WITH:

WiTH 
A0 AS (SELECT 0 as N FROM DUAL UNION ALL SELECT 0 FROM DUAL), 
A1 AS (SELECT 0 as N FROM A0, A0 AS B), 
A2 AS (SELECT 0 as N FROM A1, A1 AS B), 
A3 AS (SELECT 0 as N FROM A2, A2 AS B), 
A4 AS (SELECT 0 as N FROM A3, A3 AS B), 
A5 AS (SELECT 0 as N FROM A4, A4 AS B), 
A6 AS (SELECT 0 as N FROM A5, A5 AS B), 
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY N) AS Val FROM A6) 
SELECT * 
FROM Nums 
WHERE Val <= :NUM 
; 
+0

Co się stanie, jeśli przekażę 100 jako: NUM? – Giorgi

+0

... następnie kontynuuj wzór zgodnie z wymaganiami. Możesz użyć rekurencyjnego CTE, ale nie jestem pewien, co to jest składnia Oracle. Można również zastosować podejście typu wiersz_liczba. –

+0

@Rob: Obsługa Oracle dla rekursywnych klauzul Zaczyna 11g iirc. –

0

W zależności od bazy danych można zastosować różne metody.

PostgreSQL ma fajną funkcję - series.

Aby dostać to, co chcesz po prostu:

SELECT * FROM generate_series(1, NUM); 
+2

Myślę, że z wzmianki o "PL/SQL" i "podwójnym" stole, który chce rozwiązania dla Oracle. –

0

mam oznakowanie tej Wiki, ponieważ w rzeczywistości nie odpowiedzieć na zapotrzebowanie na nie stołach, ale jedną z pierwszych rzeczy, które możemy zrobić podczas instalacji baza danych to utworzenie zestawu tabel dla tego celu.

  • Tabela zawierająca dużą liczbę liczb całkowitych (np. -99999 do 99999).
  • Tabela zawierająca każdą datę od 10 lat w przeszłości do 10 lat w przyszłości (która jest dodawana w sposób ciągły do ​​każdego miesiąca i czasami przycinana).
  • Tabela zawierająca każdą godzinę dnia.

Dzięki temu znacznie zmniejszamy złożoność i zwiększamy prędkość wielu zapytań kosztem (minimalnej i taniej) przestrzeni dyskowej.

Powinieneś poważnie się nad tym zastanowić. Oprócz utrzymywania tabeli dat nie trzeba dużo dbać.

+1

DUAL to najlepszy sposób na zrobienie tego rodzaju rzeczy - w 10g + Oracle daje FAST DUAL, który obejmuje odczyty zerowymi blokami. DUAL prawie zawsze będzie lepiej niż w przypadku stołów domowych. –

+1

Bez wątpienia, ale nie używamy tylko Oracle. Rozwiązanie, które mamy, jest niezależne od dostawcy i działa więcej niż wystarczająco szybko. – paxdiablo

3

Nie wymyśliłem tej odpowiedzi [więc upewnij się, że wszystkie głosy idą w dobrą stronę !!], to tylko moje notatki testowe oparte na "Kucykach OMG" [którzy nie byli pewni, czy metoda będzie działać z wiązanie zmienna] powyżej dla odniesienia:

Connected to: 
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production 
With the Partitioning, OLAP and Data Mining options 

SQL> var num_rows number 
SQL> begin select 20 into :num_rows from dual; 
    2 end; 
    3/

PL/SQL procedure successfully completed. 

SQL> select level from dual 
    2 connect by level <=:num_rows; 

    LEVEL 
---------- 
     1 
     2 
     3 
     4 
... 
0

Innym rozwiązaniem byłoby wymagać pewnej PL/SQL, aby utworzyć funkcję, która zwraca kolekcję z wierszy ... Nie takie proste podejście select level from dual connect by level <= :b1, ale jest przydatny w kilku sytuacje:

1) Utwórz typ obiektu tabeli liczb (number_tbl, w tym przykładzie):

create or replace type number_tbl as table of number; 

2) Utwórz funkcję, która otrzyma liczbę wierszy, które mają być generowane, a następnie zwraca obiekt number_tbl z wynikami:

create or replace function get_rows(i_num_rows number) return number_tbl as 
    t number_tbl := number_tbl(); 
begin 
    if i_num_rows < 1 then 
    return null; 
    end if; 

    t.extend(i_num_rows); 

    for i in 1..i_num_rows loop 
    t(i) := i; 
    end loop; 

    return t; 
end get_rows; 

3) Wybierz z funkcji przy użyciu funkcji table(...) do zamień swój obiekt number_tbl w coś do wybrania:

select * from table(cast (get_rows(:b1) as number_tbl)); 
0

połączenie przez to taka wspaniała rzecz. Pomaga w generowaniu wielu wierszy za pomocą jednego zestawu danych dostępnych w podwójnej tabeli. Może to pomóc w wygenerowaniu ogromnej liczby wierszy dla twoich fałszywych danych. Na przykład

insert into test select a.* from test1 a,(select * from dual connect by level <=100000) b; 

czy można zrobić coś takiego

przykładzie 2: Chcesz wydrukować kwadrat i sześcian z numerami od 1 do 10.

SQL> select level "No", power(level,2) "Square", power(level,3) "Cube" from dual  connect by level <= 10; 

    No  Square  Cube 
---------- ---------- ---------- 
    1   1   1 
    2   4   8 
    3   9   27 
    4   16   64 
    5   25  125 
    6   36  216 
    7   49  343 
    8   64  512 
    9   81  729 
    10  100  1000 

Stąd można manipulować w w jakiejkolwiek formie. W ten sposób można zwrócić wiele wierszy z podwójnej tabeli. Odniesienia: http://www.oraclebin.com/2012/12/multipe-rows-from-dual-table.html

1

zapytań bez połączenia przy

WITH num(n) as(select 1 from dual union all 
select n+1 from num where n <= :num_limit) 
select * from num 
0

Innym sposobem jest użycie zakres wyrażenia XQuery np

select column_value from xmltable(:a||' to '||:b); 

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 

To rozwiązanie jest bardzo elastyczne, np

select column_value from xmltable('5 to 10, 15 to 20'); 

5 
6 
7 
8 
9 
10 
15 
16 
17 
18 
19 
20