web-dev-qa-db-fra.com

Est-il possible de générer une instruction SELECT à partir d'un bloc PL/SQL?

Comment puis-je obtenir un bloc PL/SQL pour afficher les résultats d'une instruction SELECT de la même manière que si j'avais effectué un SELECT simple?

Par exemple, comment faire une SELECT comme:

SELECT foo, bar FROM foobar;

Indice:

BEGIN
SELECT foo, bar FROM foobar;
END;

ne fonctionne pas.

52
GameFreak

Cela dépend de ce dont vous avez besoin du résultat.

Si vous êtes sûr qu'il n'y aura qu'une seule ligne, utilisez le curseur implicite:

DECLARE
   v_foo foobar.foo%TYPE;
   v_bar foobar.bar%TYPE;
BEGIN
   SELECT foo,bar FROM foobar INTO v_foo, v_bar;
   -- Print the foo and bar values
   dbms_output.put_line('foo=' || v_foo || ', bar=' || v_bar);
EXCEPTION
   WHEN NO_DATA_FOUND THEN
     -- No rows selected, insert your exception handler here
   WHEN TOO_MANY_ROWS THEN
     -- More than 1 row seleced, insert your exception handler here
END;

Si vous souhaitez sélectionner plus d'une ligne, vous pouvez utiliser un curseur explicite:

DECLARE
   CURSOR cur_foobar IS
     SELECT foo, bar FROM foobar;

   v_foo foobar.foo%TYPE;
   v_bar foobar.bar%TYPE;
BEGIN
   -- Open the cursor and loop through the records
   OPEN cur_foobar;
   LOOP
      FETCH cur_foobar INTO v_foo, v_bar;
      EXIT WHEN cur_foobar%NOTFOUND;
      -- Print the foo and bar values
      dbms_output.put_line('foo=' || v_foo || ', bar=' || v_bar);
   END LOOP;
   CLOSE cur_foobar;
END;

ou utilisez un autre type de curseur:

BEGIN
   -- Open the cursor and loop through the records
   FOR v_rec IN (SELECT foo, bar FROM foobar) LOOP       
   -- Print the foo and bar values
   dbms_output.put_line('foo=' || v_rec.foo || ', bar=' || v_rec.bar);
   END LOOP;
END;
32
Sergey Stadnik

Vous pouvez le faire dans Oracle 12.1 ou une version ultérieure:

declare
    rc sys_refcursor;
begin
    open rc for select * from dual;
    dbms_sql.return_result(rc);
end;

Je n'ai pas de base de données 12.x ou DBVisualizer à tester, mais cela devrait probablement être votre point de départ.

Pour plus de détails, voir Jeux de résultats implicites dans le Guide des nouvelles fonctionnalités d'Oracle 12.1 , Blog de Tom Kyte , Oracle Base etc.

Pour les versions antérieures, selon l'outil, vous pourrez peut-être utiliser des variables de liaison du curseur ref, comme cet exemple de SQL * Plus:

set autoprint on

var rc refcursor

begin
    open :rc for select count(*) from dual;
end;
/

PL/SQL procedure successfully completed.


  COUNT(*)
----------
         1

1 row selected.
30

Créez une fonction dans un package et renvoyez un SYS_REFCURSOR:

FUNCTION Function1 return SYS_REFCURSOR IS 
       l_cursor SYS_REFCURSOR;
       BEGIN
          open l_cursor for SELECT foo,bar FROM foobar; 
          return l_cursor; 
END Function1;
7
Igor Zelaya

D'un bloc anonyme? J'aimerais maintenant parler davantage de la situation dans laquelle vous pensez que cela est nécessaire, car avec les clauses de factorisation des sous-requêtes et les vues en ligne, il est assez rare que vous ayez besoin de recourir à PL/SQL pour toute autre tâche que les situations les plus complexes.

Si vous pouvez utiliser une procédure nommée, utilisez des fonctions en pipeline. Voici un exemple tiré de la documentation:

CREATE PACKAGE pkg1 AS
  TYPE numset_t IS TABLE OF NUMBER;
  FUNCTION f1(x NUMBER) RETURN numset_t PIPELINED;
END pkg1;
/

CREATE PACKAGE BODY pkg1 AS
-- FUNCTION f1 returns a collection of elements (1,2,3,... x)
FUNCTION f1(x NUMBER) RETURN numset_t PIPELINED IS
  BEGIN
    FOR i IN 1..x LOOP
      PIPE ROW(i);
    END LOOP;
    RETURN;
  END;
END pkg1;
/

-- pipelined function is used in FROM clause of SELECT statement
SELECT * FROM TABLE(pkg1.f1(5));
6
David Aldridge

si vous voulez voir sélectionner la sortie de la requête dans pl/sql, vous devez utiliser un curseur explicite. Ce qui contiendra le jeu de données actif et en extrayant chaque ligne à la fois, il affichera tout l'enregistrement du jeu de données actif tant qu'il récupérera l'enregistrement du jeu de données en effectuant une itération en boucle. Ces données ne seront pas générées sous forme de tableau, mais le résultat sera au format texte. J'espère que cela vous sera utile. Pour toute autre question, vous pouvez demander ....

set serveroutput on;
declare
cursor c1 is
   select foo, bar from foobar;
begin
  for i in c1 loop
    dbms_output.put_line(i.foo || ' ' || i.bar);
  end loop;
end;
4
Ahsan Habib

Le bloc classique «Hello World!» Contient une section exécutable qui appelle la procédure DBMS_OUTPUT.PUT_LINE pour afficher du texte à l'écran:

BEGIN
  DBMS_OUTPUT.put_line ('Hello World!');
END;

Vous pouvez le commander ici: http://www.Oracle.com/technetwork/issue-archive/2011/11-mar/o21plsql-242570.html

4
Dinesh Katwal

Pour les versions inférieures à 12c, la réponse simple estNO, du moins pas comme SQL Server.
Vous pouvez imprimer les résultats, les insérer dans des tableaux, les retourner sous forme de curseurs depuis la fonction/la procédure ou renvoyer un ensemble de lignes depuis la fonction
mais vous ne pouvez pas exécuter une instruction SELECT sans utiliser les résultats.


Serveur SQL

begin
    select 1+1
    select 2+2
    select 3+3
end

/ * 3 jeux de résultats renvoyés * /


Oracle

SQL> begin
  2  select 1+1 from dual;
  3  end;
  4  /
select * from dual;
*
ERROR at line 2:
ORA-06550: line 2, column 1:
PLS-00428: an INTO clause is expected in this SELECT statement

utiliser l'instruction immédiate

comme: 

declare
 var1    integer;
var2 varchar2(200)
begin
 execute immediate 'select emp_id,emp_name from emp'
   into var1,var2;
 dbms_output.put_line(var1 || var2);
end;
2

Vous devez utiliser le SQL dynamique natif. De plus, vous n'avez pas besoin de BEGIN-END pour exécuter la commande SQL:

declare
  l_tabname VARCHAR2(100) := 'dual';
  l_val1    VARCHAR2(100):= '''foo''';
  l_val2    VARCHAR2(100):= '''bar''';
  l_sql     VARCHAR2(1000);  
begin
  l_sql:= 'SELECT '||l_val1||','||l_val2||' FROM '||l_tabname;
  execute immediate l_sql;
  dbms_output.put_line(l_sql);
end;
/

Output:
 SELECT 'foo','bar' FROM dual
2
Art

Même si la question est ancienne mais je partagerai la solution qui répond parfaitement à la question:

SET SERVEROUTPUT ON;

DECLARE
    RC SYS_REFCURSOR;
    Result1 varchar2(25);
    Result2 varchar2(25);
BEGIN
    OPEN RC FOR SELECT foo, bar into Result1, Result2 FROM foobar;
    DBMS_SQL.RETURN_RESULT(RC);
END;
0
Issam El omri