web-dev-qa-db-ja.com

Oracle PL / SQLで変数を使用しようとしていますが、エラーが発生します。ここで何が問題になっていますか?

私はSQL Serverの出身ですが、Oracle PL/SQL変数の使用方法を理解しようとしています。変数を宣言してから、その変数を選択しようとしています。簡単に聞こえますが、私は何か間違ったことをしています。これが私のコードです:

declare
    num number;
begin
    num := 64;        
    select num from dual; --error here
end;
/

これにより、「PLS-00428:このSELECTステートメントにはINTO句が必要です」というエラーメッセージが表示されます。

私はこれの他のいくつかの順列を試しましたが、それぞれがエラーを出します:

declare
    num number;
begin
    num := 64;
end;
select num from dual; --"num" invalid identifier
/

これもエラーになります。

declare
    num number;
begin
    num := 64;
end;
/
select num from dual; --"num" invalid identifier

ミハイのコメントに基づいて、私は宣言を最初に置いてみましたが、それもエラーをスローしました:

begin
declare
    num number;
    num := 64; --encountered symbol "=" when expecting ...
end;
/
select num from dual; --"num" invalid identifier

参考までに、SQL Serverでこれを行う方法を次に示します。明確ではないかもしれませんが、以下の@num変数のスコープは宣言を含むファイルです。この変数はグローバルではありません。

declare @num int = 64
select @num

これはDBArtisanです。この質問は this this here に似ていますが、変数をuseする方法も尋ねています。そして、私はバインド変数に興味がありません(私は思いません)。このような1回限りのクエリを記述したいと思います:select * from employee where manager_id = mgrIDは、私が宣言する変数であるmgrIDを使用します。

1
user2023861

これらの回答はすべて、a)非常に複雑になっており、b)user2023861が達成したいことと比較して、軌道に乗っていないと思います。

「変数を宣言してから、その変数を選択しようとしています。」 PL/SQLまたはSQLplusのいずれかで2つの異なることを意味し、DBArtisanでさらに2つのことを意味します。 SQLplusで目的を達成するには、「置換変数」を使用します... 優れた背景がここにあります。

私の例は、SQL Server T-SQLの例に厳密に従っていませんが、近いものであり、手続き型ではありません(読み取り:匿名のPL/SQLブロックはありません。)

PL/SQLと置換変数:

DEFINE min_salary = 1000
DEFINE mgrID = 7

select *
from employees
where
    salary > &min_salary
    and mgrID = &mgrID
;

すべてSQL-Plusプロンプトで...架空の従業員テーブルから、次の結果を得ました。

    SALARY      MGRID
---------- ----------
      2000          7
      1001          7
2 row selected.

この半手続きを作成する場合は、BIND変数と、T-SQLに類似したPL/SQLの宣言構文を使用します。 (私の意見では、これは多大な労力の浪費ですが、変数の型を明確にするために含まれています。)

PL/SQLバインド変数を使用したSQLPlus:

 VARIABLE   v_in_min_salary number;
 VARIABLE   v_mgrID         number;    /* vars are defined within SQL+ */
 VARIABLE   v_out_salary    number;
 VARIABLE   v_out_mgrID     number; 

BEGIN
    :v_in_min_salary    := 1000;   /* vars are assigned values in PL/SQL */ 
    :v_mgrID            := 7; 

 select salary, mgrID 
  into :v_out_salary, :v_out_mgrID 
  from employees 
  where salary > :v_in_min_salary and mgrID = :v_mgrID
 ;

end;
/

PRINT :v_in_min_salary   /* here the in and out vars are displayed  */
PRINT :v_mgrID
PRINT :v_out_salary
PRINT :v_out_mgrID

PL/SQLを使用した完全手続き型アプローチ:

set serveroutput on;  /* environment setting within SQLplus to see output */
DECLARE
   v_in_min_salary number   := 1000;
   v_mgrID    number        :=7; 
   v_out_salary number;
   v_out_mgrID    number; 

BEGIN
  SELECT salary, mgrID 
    into :v_out_salary, :v_out_mgrID 
    from employees 
    where salary > :v_in_min_salary and mgrID = :v_mgrID
  ;
  DBMS_OUTPUT.PUT_LINE('Salary Output is= '||:v_out_salary);
  DBMS_OUTPUT.PUT_LINE('Manager ID = '||:v_out_mgrID);
END;
/

それで、いつそれぞれの場合を使うのですか?入力をパラメーター化するSQLスクリプトを作成するときは、75%の確率でSQLplus Substitution変数を使用します。 SQLplusプロンプトでスクリプトを実行すると、入力引数を渡すことができるため、次の例のように、私のお気に入りの置換変数は&1と&2です。

   @get_table_size.sql <schema> <table_name>  
        which in practice becomes 
   @get_table_size jason employees

と同様のSQLコードを実行します

SELECT extents 
  FROM all_tables 
  WHERE UPPER(table_owner) = upper('&1')  /* inbound first argument */
  and UPPER(table_name) = upper('&2')     /* inbound 2nd argument   */
;

インバウンド引数がどのように置換変数に割り当てられ、SQLステートメントで使用されるかに注意してください。私は真ん中の例を決して使用せず、関数、プロシージャ、およびパッケージを作成するときは常に3番目の例(手続き型PL/SQL)を使用します。

3
JasonInVegas

最初の試みは、無名PL/SQLブロックの正しい構文です。

エラーメッセージ

このSELECTステートメントにはINTO句が必要です

問題が何であるかを正確にあなたに言いました。

ストアドプロシージャ(またはPL/SQLブロック)内で単に「選択」して、そこから結果を魔法のように「返す」ことはできません。これは、PL/SQLとT-SQLの根本的な違いです。

プロシージャが結果を返すようにする場合は、出力パラメータとしてREF CURSORが必要か、結果セットを返す関数を作成する必要があります。ただし、どちらの場合も、プロシージャ/関数を呼び出すだけではできません。プロシージャがREF CURSORを返すか、テーブルの代わりに明示的に使用する場合、呼び出し元は結果を何らかの形で消費する必要があります。 select * from table(my_function());

ここに私がまとめたオプションがあります。これは仕事を終わらせ、醜い定型コードを回避します。

with vars as
(
    select 
        1000  v_min,
        7     v_mgrID
    from dual
)

select *
from employees
where 
    salary > (select v_min from vars)
    and mgrID = (select v_mgrID from vars)

これは最もパフォーマンスの高いコードではないかもしれませんが、理解するのは簡単です。変数の読み書きに関するPL/SQLのドキュメントは非常に貧弱であることがわかりました。私は間違いを証明して喜んでいますが、次のTSQLコードで示されているのと同じ概念を含むPL/SQLコードの簡単な例を見つけることができません。

declare @min_salary int = 1000
declare @mgrID int = 7

select *
from employees
where
    salary > @min_salary
    and mgrID = @mgrID

このコードを使用すると、カーソル、ループ、コードブロックについて知る必要はありません。

2
user2023861