2010-01-28 88 views
23

tengo esta tabla:¿Cómo devolver un conjunto de resultados/cursor desde un bloque anónimo Oracle PL/SQL que ejecuta SQL dinámico?

ALLITEMS 
--------------- 
ItemId | Areas 
--------------- 
1  | EAST 
2  | EAST 
3  | SOUTH 
4  | WEST 

El DDL:

drop table allitems; 

Create Table Allitems(ItemId Int,areas Varchar2(20)); 
Insert Into Allitems(Itemid,Areas) Values(1,'east'); 
Insert Into Allitems(ItemId,areas) Values(2,'east'); 
insert into allitems(ItemId,areas) values(3,'south'); 
insert into allitems(ItemId,areas) values(4,'east'); 

En MSSQL, para obtener un cursor de un SQL dinámico que puedo hacer:

DECLARE @v_sqlStatement VARCHAR(2000); 
SET @v_Sqlstatement = 'SELECT * FROM ALLITEMS'; 
EXEC (@v_sqlStatement); --returns a resultset/cursor, just like calling SELECT 

En Oracle, me necesita utilizar un bloque PL/SQL:

SET AUTOPRINT ON; 
DECLARE 
V_Sqlstatement Varchar2(2000); 
outputData SYS_REFCURSOR; 
BEGIN 
V_Sqlstatement := 'SELECT * FROM ALLITEMS'; 
OPEN outputData for v_Sqlstatement; 
End; 
--result is : anonymous block completed 

Pero todo lo que obtengo es "bloque anónimo completado".
¿Cómo obtengo que regrese el cursor?
(sé que si hago AUTOPRINT, se imprimirá la información en el REFCURSOR (éste no se imprime en el código anterior, pero eso es otro problema))

te llamaré este SQL dinámico de código (ODBC, C++), y necesito devolver un cursor.
¿Cómo hago esto? Estoy perplejo.

Respuesta

36

Puede escribir una función PL/SQL para devolver ese cursor (o se puede poner esa función en un paquete si usted tiene más código relacionado con esto):

CREATE OR REPLACE FUNCTION get_allitems 
    RETURN SYS_REFCURSOR 
AS 
    my_cursor SYS_REFCURSOR; 
BEGIN 
    OPEN my_cursor FOR SELECT * FROM allitems; 
    RETURN my_cursor; 
END get_allitems; 

Esto devolverá el cursor.

Asegúrese de no poner su SELECT -String en comillas en PL/SQL cuando sea posible. Ponerlo en cadenas significa que no se puede verificar en tiempo de compilación, y que se debe analizar cada vez que lo use.


Si realmente necesita utilizar SQL dinámico puede poner su consulta entre comillas simples:

OPEN my_cursor FOR 'SELECT * FROM allitems'; 

Esta cadena tiene que ser analizada cada vez que la función se llama, que normalmente será más lento y cueros errores en su consulta hasta el tiempo de ejecución.

asegúrese de usar bind variables siempre que sea posible para evitar hard parses:

OPEN my_cursor FOR 'SELECT * FROM allitems WHERE id = :id' USING my_id; 
+0

Gracias! Voy a intentar esto. – Liao

+0

@ Peter Lang: ¿Cómo llamaría a la función en este caso? – MissPiplup

+0

@MissPiplup: he arreglado el enlace roto, ¿esto te ayuda? –

8

en SQL * Plus también se puede utilizar una variable REFCURSOR:

SQL> VARIABLE x REFCURSOR 
SQL> DECLARE 
    2 V_Sqlstatement Varchar2(2000); 
    3 BEGIN 
    4 V_Sqlstatement := 'SELECT * FROM DUAL'; 
    5 OPEN :x for v_Sqlstatement; 
    6 End; 
    7/

ProcÚdure PL/SQL terminÚe avec succÞs. 

SQL> print x; 

D 
- 
X 
+0

¿Pero la "impresión x" devuelve un cursor? Necesito llamar a este bloque PL/SQL desde código C++ y necesito devolver un cursor. ¿O hay una forma de acceder a "x" desde el código? – Liao

+0

@Liao: X es el cursor, debe poder acceder a él como una variable OUT si llama al bloque PL/SQL desde C++. 'print', sin embargo, es un comando SQL * Plus y no funcionará fuera de SQL * Plus. –

1

usted debería ser capaz de declarar una cursor para ser una variable de vinculación (llamados parámetros en otro DBMS ')

como Vincent escribió, usted puede hacer algo como esto:

begin 
    open :yourCursor 
    for 'SELECT "'|| :someField ||'" from yourTable where x = :y' 
     using :someFilterValue; 
end; 

Tendría que enlazar 3 vars a esa secuencia de comandos. Una cadena de entrada para "someField", un valor para "someFilterValue" y un cursor para "yourCursor" que se debe declarar como var de salida.

Lamentablemente, no tengo idea de cómo lo harías con C++.(Podría decirse afortunadamente para mí, sin embargo; ;-))

Dependiendo de la biblioteca de acceso que utilice, podría ser un dolor real o directo.

-6

Este ajuste es necesario establecer:

SET SERVEROUTPUT ON 
Cuestiones relacionadas