Можно ли вывести инструкцию SELECT из блока PL / SQL? - PullRequest
54 голосов
/ 09 декабря 2008

Как получить блок PL / SQL для вывода результатов оператора SELECT так же, как если бы я сделал простое SELECT?

Например, как сделать SELECT вроде:

SELECT foo, bar FROM foobar;

Подсказка:

BEGIN
SELECT foo, bar FROM foobar;
END;

не работает.

Ответы [ 10 ]

36 голосов
/ 09 декабря 2008

Зависит от того, для чего вам нужен результат.

Если вы уверены, что будет только 1 строка, используйте неявный курсор:

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;

Если вы хотите выбрать более 1 строки, вы можете использовать либо явный курсор:

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;

или используйте другой тип курсора:

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;
31 голосов
/ 01 ноября 2016

Вы можете сделать это в Oracle 12.1 или выше:

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

У меня нет базы данных 12.x или DBVisualizer для тестирования, но это, вероятно, должно быть вашей отправной точкой.

Подробнее см. В разделе Неявные наборы результатов в Руководстве по новым функциям Oracle 12.1 , Блог Тома Кайта , База Oracle и т. Д.

В более ранних версиях, в зависимости от инструмента, вы можете использовать переменные привязки курсора ref, как в этом примере из 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.
7 голосов
/ 09 декабря 2008

Из анонимного блока? Теперь я хотел бы подробнее рассказать о ситуации, когда вы считаете, что это необходимо, поскольку с помощью факторинговых подзапросов и встроенных представлений довольно редко вам приходится прибегать к PL / SQL для чего-либо, кроме самых сложных ситуаций.

Если вы можете использовать именованную процедуру, используйте конвейерные функции. Вот пример, извлеченный из документации:

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));
7 голосов
/ 09 декабря 2008

Создать функцию в пакете и вернуть 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;
4 голосов
/ 05 ноября 2016

Если вы хотите увидеть вывод запроса select в pl / sql, вам нужно использовать явный курсор. Который будет содержать активный набор данных и, выбирая каждую строку за раз, будет показывать всю запись из активного набора данных, пока он выбирает запись из набора данных, повторяя в цикле. Эти данные не будут сгенерированы в табличном формате, этот результат будет в текстовом формате. Надеюсь, это будет полезно. Для любого другого запроса вы можете спросить ....

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 голосов
/ 04 ноября 2016

Классический блок «Hello World!» Содержит исполняемый раздел, который вызывает процедуру DBMS_OUTPUT.PUT_LINE для отображения текста на экране:

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

Вы можете оформить заказ здесь: http://www.oracle.com/technetwork/issue-archive/2011/11-mar/o21plsql-242570.html

3 голосов
/ 01 ноября 2016

Для версий ниже 12с простой ответ - НЕТ , по крайней мере, не так, как это делается в SQL Server.
Вы можете распечатать результаты, вы можете вставить результаты в таблицы, вы можете вернуть результаты в виде курсоров из функции / процедуры или вернуть набор строк из функции -
но вы не можете выполнить инструкцию SELECT, ничего не делая с результатами.


SQL Server

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

/ * возвращены 3 набора результатов * /


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
2 голосов
/ 03 ноября 2016

использовать команду немедленного выполнения

нравится:

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 голосов
/ 02 ноября 2016

Вам необходимо использовать собственный динамический SQL. Кроме того, вам не нужен BEGIN-END для запуска команды 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
0 голосов
/ 26 июня 2018

Даже если вопрос старый, но я поделюсь решением, которое идеально ответит на вопрос:

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;
...