2009-12-29 1 views
12

Voglio scrivere una query SQL che accetta una variabile di binding (ad esempio: NUM) e il suo output è costituito da una colonna &: NUM numero di righe, ogni riga ha il suo numero di riga. vale a dire, se si passa: NUM come 7, l'uscita dovrebbe essere:SQL Query per restituire N righe da doppio

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

Non ci dovrebbe essere tutte le tabelle attuali DB in query e nessun codice PL/SQL dovrebbe essere usato. vale a dire solo dual dovrebbe essere utilizzato nella query

C'è un modo per raggiungere questo obiettivo?

+0

retagged come oracle, sperare che fosse corretto –

+0

@Rob: Postgres supporta anche PLSQL, ma non supporta 'FROM DUAL', quindi Oracle è corretto. –

+0

Grazie Rob, è corretta questa domanda era intesa solo su Oracle DB – Harish

risposta

33

si potrebbe usare:

WHERE ROWNUM <= :NUM 

... ma la tabella deve contenere fila pari o superiore al limite nella variabile bind . This link demonstrates various row number generation techniques in Oracle.

Utilizzando CONNECT BY, Oracle 10g +:

SELECT LEVEL 
    FROM DUAL 
CONNECT BY LEVEL <= :NUM 

Confermato dal monojohnny che la variabile bind può essere utilizzato. Tentativi di esecuzione su Oracle 9i, sebbene la sintassi CONNECT BY sia supportata, restituisce un errore ORA-01436.

L'unica cosa su cui non sono al 100% è se CONNECT BY accetterà il limite dalla variabile bind.

Riferimento:

+0

+1 Questo metodo è anche suggerito qui: http://www.adp-gmbh.ch/ora/sql/examples/generate_rows.html –

+0

Questo mi dà un errore per qualsiasi valore superiore a uno. 'SELEZIONA LIVELLO DA DUAL CONNECT BY LEVEL <= 20': ORA-01436 – Kobi

+1

@Kobi: Quale versione - funziona per me su 10g –

5

provare qualcosa di simile:

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; 

E 'disordinato, ma farà il trucco.

Modificato: Ah - è necessario passare a una variabile per farvi sapere quanto è alto per andare ...

Così come su qualcosa di simile:

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 ... modifica ancora una volta, ora utilizzando CON:

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

Cosa succede se passo 100 come: NUM? – Giorgi

+0

... quindi si continua il pattern come richiesto. È possibile utilizzare un CTE ricorsivo, ma non sono sicuro di quale sia la sintassi Oracle. Puoi anche usare un approccio di stile row_number. –

+0

@Rob: il supporto Oracle per le clausole ricorsive WITH inizia 11g iirc. –

0

A seconda del database, è possibile utilizzare vari metodi.

PostgreSQL ha una bella funzionalità - series.

Per ottenere quello che vuoi semplicemente desidera:

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

Penso che dalla menzione di "PL/SQL" e della tabella "doppia" voglia una soluzione per Oracle. –

0

sto segnando questo wiki comunità dal momento che in realtà non risponde alla tua esigenza di tavoli, ma una delle prime cose che facciamo quando si installa un database è creare una serie di tabelle per questo tipo di scopo.

  • Una tabella contenente un numero elevato di numeri interi (ad esempio da -99999 a 99999).
  • Una tabella contenente ogni data da 10 anni nel passato a 10 anni nel futuro (che viene aggiunta continuamente a ogni mese e ritagliata occasionalmente).
  • Una tabella contenente ogni ora del giorno.

In questo modo, riduciamo notevolmente la complessità e aumentiamo la velocità di un gran numero di query al costo di spazio su disco (minimo ed economico).

Si dovrebbe riflettere seriamente su questo. Oltre a mantenere la tabella delle date, non c'è bisogno di molta manutenzione.

+1

DUAL è il modo migliore per eseguire questo genere di cose: in 10g + Oracle fornisce FAST DUAL che prevede letture a zero blocchi. DUAL quasi sovraperformerà le tabelle fatte in casa. –

+1

Senza dubbio, ma non usiamo solo Oracle. La soluzione che abbiamo è indipendente dal venditore e funziona più che abbastanza veloce. – paxdiablo

3

Non ho trovato questa risposta [quindi assicurati che i voti vadano per il verso giusto !!], solo le mie note di prova basate su 'OMG Ponies' [che non erano sicuri se il metodo avrebbe funzionato con variabile vincolante] sopra per riferimento:

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

Un'altra soluzione richiederebbe un po 'di PL/SQL per creare una funzione per restituire un insieme con le righe ... non è così semplice come l'approccio select level from dual connect by level <= :b1, ma è utile, in alcuni situazioni:

1) Creare un tipo di oggetto tabella numerica (number_tbl, in questo esempio):

create or replace type number_tbl as table of number; 

2) Creare una funzione che riceverà il numero di righe da generare, e quindi restituire un oggetto number_tbl con i risultati:

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) selezionare la funzione utilizzando la funzione table(...) a trasforma il tuo oggetto number_tbl in qualcosa selezionabile:

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

connettersi è una cosa meravigliosa. Ti aiuta a generare più righe con un singolo set di dati disponibili nella doppia tabella. Questo può aiutarti a generare un numero enorme di righe per i tuoi dati fittizi. Per esempio

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

o si può fare qualcosa di simile

Esempio 2: Si desidera stampare quadrate e cubiche di numeri da 1 a 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 

Quindi si può manipolare in qualunque forma tu voglia. In questo modo è possibile restituire più righe dalla doppia tabella. Riferimenti: http://www.oraclebin.com/2012/12/multipe-rows-from-dual-table.html

1

Query senza connessione da

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

Un altro modo è quello di usare un'espressione di intervallo XQuery, ad esempio:

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

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 

Questa soluzione è molto flessibile, ad esempio:

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

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