78

我怎样才能得到一个 PL/SQL 块来输出一个SELECT语句的结果,就像我做了一个普通的一样SELECT

例如如何做一个SELECT喜欢:

SELECT foo, bar FROM foobar;

暗示 :

BEGIN
SELECT foo, bar FROM foobar;
END;

不起作用。

4

11 回答 11

58

您可以在 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等。

对于早期版本,根据工具的不同,您可能可以使用引用游标绑定变量,例如 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.
于 2016-11-01T12:53:34.047 回答
47

It depends on what you need the result for.

If you are sure that there's going to be only 1 row, use implicit cursor:

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;

If you want to select more than 1 row, you can use either an explicit cursor:

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;

or use another type of cursor:

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;
于 2008-12-09T04:09:39.827 回答
9

在包中创建一个函数并返回一个 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;
于 2008-12-09T05:26:54.177 回答
8

来自匿名区块?我现在想更多地了解您认为需要这样做的情况,因为对于子查询分解子句和内联视图,除了最复杂的情​​况之外,您很少需要求助于 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));
于 2008-12-09T17:54:02.563 回答
5

如果您想在 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;
于 2016-11-05T13:34:14.323 回答
4

经典的“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

于 2016-11-04T05:55:31.407 回答
4

对于 12c 以下的版本,简单的答案是NO,至少不是以 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
于 2016-11-01T04:58:19.540 回答
2

您需要使用本机动态 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
于 2016-11-02T19:00:52.340 回答
1

使用执行立即语句

喜欢:

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;
于 2016-11-03T17:02:02.113 回答
0

即使问题很老,但我会分享完美回答问题的解决方案:

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;
于 2018-06-26T12:44:25.727 回答
0

当您的选择查询返回多行时使用游标。因此,如果您想要聚合或单行数据,您可以使用没有游标的过程/函数,而不是使用游标

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

然后简单地调用程序

   Begin
   sample(20);
   End

这是过程/函数的实际使用,主要是包装和存储复杂的查询,或者需要使用相同的逻辑但不同的数据进行重复操作

于 2019-10-06T13:35:30.407 回答