2009-12-29 17 views
12

Quiero escribir una consulta SQL que acepte una variable de vinculación (digamos: NUM) y su resultado consiste en una columna &: NUM número de filas, cada fila tiene su número de fila. es decir, si pasamos NUM como 7, la salida debe ser:Consulta SQL para devolver N filas de

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

No debería haber ninguna tabla de base de datos reales en la consulta y no hay código PL/SQL se debe utilizar. es decir, solo dual debe usarse en la consulta

¿Hay alguna forma de lograr esto?

+0

retenido como oráculo, espero que sea correcto –

+0

@Rob: Postgres también es compatible con PLSQL, pero no admite 'FROM DUAL', por lo que Oracle es correcto. –

+0

Gracias Rob, es correcto, esta pregunta solo se refería a Oracle DB – Harish

Respuesta

33

que puede usar:

WHERE ROWNUM <= :NUM 

... pero la mesa tiene que contener fila igual o mayor que el límite de la variable de vinculación . This link demonstrates various row number generation techniques in Oracle.

Usando CONNECT BY, Oracle 10g +:

SELECT LEVEL 
    FROM DUAL 
CONNECT BY LEVEL <= :NUM 

confirmado por monojohnny que la variable de enlace puede ser utilizado. Los intentos de ejecutar en Oracle 9i, aunque se admite la sintaxis CONNECT BY, da como resultado un error ORA-01436.

Lo único que no estoy al 100% es si CONNECT BY aceptará el límite de la variable de vinculación.

Referencia:

+0

+1 Este método también se sugiere aquí: http://www.adp-gmbh.ch/ora/sql/examples/generate_rows.html –

+0

Esto me da un error para cualquier valor superior a uno. 'SELECCIONE EL NIVEL DE DUAL CONNECT BY LEVEL <= 20': ORA-01436 – Kobi

+1

@Kobi: ¿Qué versión? Funciona para mí en 10g –

5

intentar algo como:

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; 

Es complicado, pero que va a hacer el truco.

Editado: Ah - que necesita para pasar de una variable para hacerle saber qué tan alto para ir ...

Entonces, ¿cómo de algo como:

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 ... la edición de nuevo, ahora con 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

¿Qué pasa si paso 100 como: NUM? – Giorgi

+0

... luego continúa el patrón según sea necesario. Podría usar un CTE recursivo, pero no estoy seguro de cuál es la sintaxis de Oracle para eso. También podría usar un enfoque de estilo row_number. –

+0

@Rob: el soporte de Oracle para cláusulas WITH recursivas inicia 11g iirc. –

0

Depende de la base de datos se pueden usar varios métodos.

PostgreSQL tiene una buena característica - series.

Para obtener lo que desea que desea es:

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

Creo que por la mención de 'PL/SQL' y la tabla 'dual' que él quiere una solución para Oracle. –

0

estoy marcando esta comunidad wiki, ya que en realidad no responder a su necesidad de ninguna tabla, pero una de las primeras cosas que hacemos cuando se instala una la base de datos es crear un conjunto de tablas para este tipo de propósito.

  • Una tabla que contiene una gran cantidad de enteros (por ejemplo, -99999 a 99999).
  • Una tabla que contiene cada fecha de 10 años en el pasado a 10 años en el futuro (que se agrega continuamente a cada mes y se recorta ocasionalmente).
  • Una tabla que contiene cada hora del día.

Al hacer esto, reducimos en gran medida la complejidad y aumentamos la velocidad de un gran número de consultas a cambio de espacio de disco (mínimo y económico).

Deberías pensarlo seriamente. Además de mantener la tabla de fechas, no se necesita mucho mantenimiento.

+1

DUAL es la mejor manera de realizar este tipo de cosas: en 10g + Oracle otorga FAST DUAL, lo que implica cero lecturas de bloque. DUAL casi siempre superará las tablas hechas en casa. –

+1

Sin duda, pero no usamos solo Oracle. La solución que tenemos es independiente del proveedor y funciona más que suficientemente rápido. – paxdiablo

3

No se me ocurrió esta respuesta [así que asegúrese de que los votos vayan de la manera correcta !!], solo mis notas de prueba basadas en 'OMG Ponies' [que no estaba seguro de si el método funcionaría con enlace variable] arriba para referencia:

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

Otra solución requeriría alguna PL/SQL para crear una función para devolver una colección con las filas ... No es tan simple como el enfoque select level from dual connect by level <= :b1, pero es útil en algunos situaciones:

1) Cree un tipo de objeto de tabla numérica (number_tbl, en este ejemplo):

create or replace type number_tbl as table of number; 

2) Crear una función que va a recibir el número de filas que se genera, y luego devolver un objeto number_tbl con los resultados:

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) seleccionar de su función usando la función table(...) a convierta su objeto number_tbl en algo seleccionable:

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

connect by es una cosa tan maravillosa. Le ayuda a generar múltiples filas con un único conjunto de datos disponibles en la tabla dual. Esto puede ayudarlo a generar un gran número de filas para sus datos ficticios. Por ejemplo

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

o puede hacer algo como esto

Ejemplo 2: Se desea imprimir cuadrado y el cubo de números del 1 al 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 

Por lo tanto se puede manipular de cualquier forma que quieras Así es como puede devolver varias filas de la tabla dual. Referencias: http://www.oraclebin.com/2012/12/multipe-rows-from-dual-table.html

1

consulta sin conexión por

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

Otra forma es utilizar una expresión gama XQuery, por ejemplo:

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

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 

Esta solución es bastante flexible, por ejemplo:

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

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