Можно ли вывести оператор SELECT из блока PL/SQL?

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

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

SELECT foo, bar FROM foobar;

Намекать :

BEGIN
SELECT foo, bar FROM foobar;
END;

не работает.


person GameFreak    schedule 09.12.2008    source источник
comment
Я не чувствую, что кто-либо из ответивших ответил на этот вопрос. Я новичок в PL/SQL, и мне трудно понять, как получить набор результатов из простого оператора select, чтобы он отображался в DBVisualizer, когда он выполняется внутри блока PL/SQL. Это может быть довольно простой ответ, но как пользователь MSSQL я здесь потерялся. Я немного пробовал гуглить, но не наткнулся на ответ, иначе я бы добавил его сам.   -  person Spencer Ruport    schedule 01.11.2016
comment
Ответ Сергея довольно исчерпывающий, но вы хотели бы увидеть его в аналогичном инструменте (SQL Developer vs DBVisualizer), проверьте это thatjeffsmith.com/archive/2012/03/dbms_output-in-sql-developer   -  person Scott    schedule 01.11.2016
comment
Если вы работаете с одним блоком PL/SQL и, возможно, используете Oracle SQL Developer для доступа к базе данных с помощью dbms_output.put_line(), то как вы это сделаете. С другой стороны, если вы компилируете этот код в базу данных Oracle как пакет или функцию, вы должны PIPE вывести данные, используя PIPE ROW(r);   -  person Code Novice    schedule 02.05.2019


Ответы (11)


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

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

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

Дополнительные сведения см. в разделе Неявные наборы результатов в Руководстве по новым функциям Oracle 12.1, Oracle Base и т. д.

Для более ранних версий, в зависимости от инструмента, вы можете использовать переменные привязки курсора 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.
person William Robertson    schedule 01.11.2016
comment
Спасибо! Есть ли другой подход, обеспечивающий такое же поведение в 10.2? На самом деле все, что я пытаюсь сделать, это выяснить, как выполнять запросы с переменными SQL изнутри DBVisualizer. - person Spencer Ruport; 01.11.2016
comment
Отображает ли DBVis курсоры ссылок, такие как SQL*Plus и PL/SQL Developer? (Добавленный пример.) В PL/SQL Developer вы должны ввести блок PL/SQL в тестовое окно и добавить переменную rc в качестве курсора на нижнюю панель, а затем после выполнения блока вы можете щелкнуть по переменной. - person William Robertson; 01.11.2016
comment
Я не уверен, но дополнительная информация была бы полезна, даже если она не относится к DBVisiaulizer, поэтому давайте согласимся. - person Spencer Ruport; 01.11.2016
comment
Еще раз спасибо! Попробую! :) (Награда за вами. Она разблокируется через 8 часов.) - person Spencer Ruport; 01.11.2016
comment
Почему у меня не работает первый вариант, вывод rc? Он выполняется, но не показывает результата. Oracle 12c Enterprise 12.1.0.2.0 — 64-разрядная версия - person TPAKTOPA; 04.02.2021
comment
@TPAKTOPA, какой клиентский инструмент вы используете? Инструмент должен знать об этой функции. - person William Robertson; 04.02.2021
comment
@WilliamRobertson TOAD, но я нашел причину странного поведения. Я сохранил свои временные SQL в файле с расширением .SQL. Похоже, что запутанный TOAD, и он не работал должным образом с одиночными SQL. Открываю новое окно редактора, вставляю туда код - все работает. Также моя ЖАБА отстает от версии на много лет - ограничения на обновление ПО на рабочих машинах. - person TPAKTOPA; 17.02.2021

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

Если вы уверены, что будет только 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;
person Sergey Stadnik    schedule 09.12.2008
comment
Кроме того, если вы используете SQLPlus для запуска этого, вам нужно установить SERVEROUTPUT ON, чтобы увидеть вывод. Другие клиенты могут иметь аналогичные параметры, которые необходимо включить. - person Dave Costa; 09.12.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));
person David Aldridge    schedule 09.12.2008
comment
С точки зрения Oracle вы правы на 100%. Однако, проведя свои первые 5 лет с Oracle и следующие 5 «роскошных» лет с SQL Server, я думаю, что жизнь была бы проще [хотя и не корректной с точки зрения программирования], если бы Oracle позволила такое. :) - person tjeloep; 05.08.2015

Создайте функцию в пакете и верните 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;
person Igor Zelaya    schedule 09.12.2008

если вы хотите увидеть вывод запроса 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;
person Ahsan Habib    schedule 05.11.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

person Dinesh Katwal    schedule 04.11.2016
comment
Извините. И это только для базы данных Oracle. Это очень полезно для меня для блока Pl/sql. - person Dinesh Katwal; 04.11.2016

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


SQL-сервер

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

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


Оракул

SQL> begin
  2  select * 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
person David דודו Markovitz    schedule 01.11.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
person Art    schedule 02.11.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;
person Vamsi Praveen Karanam    schedule 03.11.2016
comment
здесь нет необходимости использовать динамический sql! Это должно быть выбрано ... в ... заявление. - person Rusty; 08.11.2016

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

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;
person Issam El omri    schedule 26.06.2018

Курсоры используются, когда ваш запрос на выборку возвращает несколько строк. Таким образом, вместо использования курсора в случае, если вам нужны агрегаты или отдельные данные строки, вы можете использовать процедуру/функцию без курсора, например

  Create Procedure sample(id 
    varchar2(20))as 
    Select count(*) into x from table 
    where 
       Userid=id;
     End ;

А затем просто вызовите процедуру

   Begin
   sample(20);
   End

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

person Himanshu Ahuja    schedule 06.10.2019