2010-01-28 5 views
23

J'ai ce tableau:Comment renvoyer un ensemble de résultats/curseur à partir d'un bloc anonyme Oracle PL/SQL qui exécute Dynamic SQL?

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

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, pour obtenir un curseur à partir d'un SQL dynamique que je peux faire:

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

Dans Oracle, je besoin d'utiliser un bloc 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 

Mais tout ce que je reçois est "bloc anonyme terminé".
Comment l'obtenir pour renvoyer le curseur?
(je sais que si je fais AUTOPRINT, il affichera les informations contenues dans refcursor (ce n'est pas l'impression dans le code ci-dessus, mais c'est un autre problème))

Je vais demander cette dynamique SQL à partir du code (ODBC, C++), et j'en ai besoin pour retourner un curseur.
Comment est-ce que je fais ceci? Je suis perplexe.

Répondre

36

Vous pouvez écrire une fonction PL/SQL pour retourner ce curseur (ou vous pouvez mettre cette fonction dans un paquet si vous avez plus de code lié à ce sujet):

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; 

Ceci renverra le curseur.

Assurez-vous de ne pas mettre votre SELECT -String entre guillemets en PL/SQL si possible. Le mettre dans des chaînes signifie qu'il ne peut pas être vérifié au moment de la compilation, et qu'il doit être analysé chaque fois que vous l'utilisez.


Si vous avez vraiment besoin d'utiliser SQL dynamique, vous pouvez mettre votre requête entre guillemets simples:

OPEN my_cursor FOR 'SELECT * FROM allitems'; 

Cette chaîne doit être analysé chaque fois que la fonction est appelée, qui sera généralement plus lent et peaux des erreurs dans votre requête jusqu'à l'exécution.

Assurez-vous d'utiliser bind-variables, si possible, pour éviter hard parses:

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

Merci! Je vais essayer ça. – Liao

+0

@Peter Lang: Comment appelleriez-vous la fonction dans ce cas? – MissPiplup

+0

@MissPiplup: J'ai réparé le lien cassé, est-ce que cela vous aide? –

8

dans SQL * Plus vous pouvez aussi utiliser une 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

Mais "print x" renvoie-t-il un curseur? J'ai besoin d'appeler ce bloc PL/SQL du code C++ et donc j'en ai besoin pour retourner un curseur. Ou y a-t-il un moyen d'accéder à "x" à partir du code? – Liao

+0

@Liao: X est le curseur, vous devriez pouvoir y accéder comme une variable OUT si vous appelez le bloc PL/SQL de C++. 'print' est cependant une commande SQL * Plus et ne fonctionnera pas en dehors de SQL * Plus. –

1

Vous devriez être en mesure de déclarer curseur pour être une variable de liaison (appelée paramètres dans d'autres SGBD ')

comme Vincent a écrit, vous pouvez faire quelque chose comme:

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

Vous devez associer 3 variables à ce script. Une chaîne d'entrée pour "someField", une valeur pour "someFilterValue" et un curseur pour "yourCursor" qui doit être déclaré en sortie var.

Malheureusement, je ne sais pas comment vous le feriez en C++.(On pourrait dire heureusement pour moi, cependant; ;-))

Selon la bibliothèque d'accès que vous utilisez, il peut être une douleur royale ou simple.

-6

Ce paramètre doit être réglé:

SET SERVEROUTPUT ON 
Questions connexes