如何从执行动态 SQL 的 Oracle PL/SQL 匿名块返回结果集/游标?

发布于 2024-08-19 19:02:38 字数 1214 浏览 8 评论 0原文

我有这个表:

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

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

在 MSSQL 中,要从动态 SQL 中获取游标,我可以这样做:

DECLARE @v_sqlStatement VARCHAR(2000);
SET @v_Sqlstatement = 'SELECT * FROM ALLITEMS';
EXEC (@v_sqlStatement); --returns a resultset/cursor, just like calling SELECT 

在 Oracle 中,我需要使用 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

**但我得到的是

匿名区块已完成”。

我如何让它返回光标?

我知道如果我执行 AUTOPRINT,它会打印出 REFCURSOR 中的信息(它不会在上面的代码中打印,但这是另一个问题)

我将从代码(ODBC,C++)调用此动态SQL,并且我需要它返回游标如何?

I have this table:

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

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

In MSSQL, to get a cursor from a dynamic SQL I can do:

DECLARE @v_sqlStatement VARCHAR(2000);
SET @v_Sqlstatement = 'SELECT * FROM ALLITEMS';
EXEC (@v_sqlStatement); --returns a resultset/cursor, just like calling SELECT 

In Oracle, I need to use a PL/SQL Block:

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

**But all I get is

anonymous block completed".

How do I get it to return the cursor?

(I know that if I do AUTOPRINT, it will print out the information in the REFCURSOR (it's not printing in the code above, but thats another problem))

I will be calling this Dynamic SQL from code (ODBC,C++), and I need it to return a cursor. How?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我为君王 2024-08-26 19:02:38

您可以编写一个 PL/SQL 函数来返回该游标(或者,如果您有更多与此相关的代码,则可以将该函数放入一个包中):

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;

这将返回游标。

确保尽可能不要将 SELECT-String 放入 PL/SQL 中的引号中。将其放入字符串中意味着无法在编译时对其进行检查,并且每次使用时都必须对其进行解析。


如果您确实需要使用动态 SQL,您可以将查询放在单引号中:

  OPEN my_cursor FOR 'SELECT * FROM allitems';

每当调用函数时都必须解析该字符串,这通常会比较慢,并且会在运行时隐藏查询中的错误。

确保尽可能使用绑定变量,以避免 硬解析

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

You can write a PL/SQL function to return that cursor (or you could put that function in a package if you have more code related to this):

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;

This will return the cursor.

Make sure not to put your SELECT-String into quotes in PL/SQL when possible. Putting it in strings means that it can not be checked at compile time, and that it has to be parsed whenever you use it.


If you really need to use dynamic SQL you can put your query in single quotes:

  OPEN my_cursor FOR 'SELECT * FROM allitems';

This string has to be parsed whenever the function is called, which will usually be slower and hides errors in your query until runtime.

Make sure to use bind-variables where possible to avoid hard parses:

  OPEN my_cursor FOR 'SELECT * FROM allitems WHERE id = :id' USING my_id;
违心° 2024-08-26 19:02:38

在 SQL*Plus 中,您还可以使用 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

in SQL*Plus you could also use a REFCURSOR variable:

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
零時差 2024-08-26 19:02:38

您应该能够将游标声明为绑定变量(在其他 DBMS 中称为参数),

就像 Vincent 所写的那样,您可以执行以下操作:

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

您必须将 3 个变量绑定到该脚本。 “someField”的输入字符串、“someFilterValue”的值和“yourCursor”的游标(必须声明为输出变量)。

不幸的是,我不知道如何从 C++ 中做到这一点。 (不过,有人可以说对我来说是幸运的。;-))

根据您使用的访问库,这可能是一种巨大的痛苦,也可能是直接的。

You should be able to declare a cursor to be a bind variable (called parameters in other DBMS')

like Vincent wrote, you can do something like this:

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

You'd have to bind 3 vars to that script. An input string for "someField", a value for "someFilterValue" and an cursor for "yourCursor" which has to be declared as output var.

Unfortunately, I have no idea how you'd do that from C++. (One could say fortunately for me, though. ;-) )

Depending on which access library you use, it might be a royal pain or straight forward.

幻梦 2024-08-26 19:02:38

需要设置此设置:

SET SERVEROUTPUT ON 

This setting needs to be set:

SET SERVEROUTPUT ON 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文