web-dev-qa-db-ja.com

動的SQLを実行するOracle PL / SQL無名ブロックから結果セット/カーソルを返す方法

私はこの表を持っています:

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の情報が出力されることがわかります(上記のコードでは印刷されませんが、別の問題です))

この動的SQLをコード(ODBC、C++)から呼び出すことになり、カーソルを返すために必要になります。
これを行うにはどうすればよいですか?私は困惑しています。

23
Liao

そのカーソルを返す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;
41
Peter Lang

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
8
Vincent Malgrat

カーソルをバインド変数(他のDBMSのパラメーターと呼ばれる)として宣言できる必要があります。

vincentが書いたように、次のようなことができます。

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

そのスクリプトに3つの変数をバインドする必要があります。 「someField」の入力文字列、「someFilterValue」の値、および出力変数として宣言する必要のある「yourCursor」のカーソル。

残念ながら、C++からそれをどのように行うかはわかりません。 (しかし、私にとって幸いなことに言えます。;-))

使用するアクセスライブラリに応じて、それは王室の痛みであるか、簡単な場合があります。

1
Robert Giesecke