web-dev-qa-db-fra.com

Comment renvoyer un jeu de résultats / curseur à partir d'un bloc anonyme Oracle PL / SQL qui exécute Dynamic SQL?

J'ai ce tableau:

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

Le 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');

Dans MSSQL, pour obtenir un curseur à partir d'un SQL dynamique, 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 dois 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 puis-je faire revenir le curseur?
(Je sais que si je fais de l'impression automatique, il imprimera les informations dans le REFCURSOR (il n'imprime pas dans le code ci-dessus, mais c'est un autre problème))

J'appellerai ce Dynamic SQL à partir du code (ODBC, C++), et j'en ai besoin pour retourner un curseur.
Comment puis-je faire cela? Je suis perplexe.

23
Liao

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

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;

Cela renverra le curseur.

Assurez-vous de ne pas mettre votre SELECT- chaîne entre guillemets en PL/SQL lorsque cela est 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 du SQL dynamique, vous pouvez mettre votre requête entre guillemets simples:

  OPEN my_cursor FOR 'SELECT * FROM allitems';

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

Assurez-vous d'utiliser des variables de liaison dans la mesure du possible pour éviter analyses rigides :

  OPEN my_cursor FOR 'SELECT * FROM allitems WHERE id = :id' USING my_id;
41
Peter Lang

dans SQL * Plus, vous pouvez également 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
8
Vincent Malgrat

Vous devriez pouvoir déclarer un curseur comme variable de liaison (appelés paramètres dans d'autres SGBD ')

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

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

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

Malheureusement, je n'ai aucune idée de la façon dont vous procéderiez à partir de C++. (On pourrait dire heureusement pour moi, cependant. ;-))

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

1
Robert Giesecke