rm /blog

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【Oracle】PL/SQLの基本的なメモ

OraclePL/SQL使う時の基本的なメモ


 

 
(1)文法構成
「begin」で始まり「end:<改行>/」で終わる。
最後の「end」はセミコロンと改行と最終行のスラッシュ('/')が必要である。

set serveroutput on;

begin
    DBMS_OUTPUT.PUT_LINE('TEST');
end;
/


sqlplusで↑をそのままコピって貼り付けると実行できる。
やってることは画面に「TEST」って表示させるだけである。

一部を除いて行の最後にはセミコロンが必要である。
(つけないと怒られる)

なお、デフォルトだとDBMS_OUTPUTの結果は画面に表示されないので、
実行前にsqlplusのオプション「serveroutput」をONにしている。




(2)変数定義
「declare」というブロックを、beginよりも前に記述して、その中で変数名や型を定義する。

set serveroutput on;
declare
    test_char char(10) := 'TEST';
begin

    DBMS_OUTPUT.PUT_LINE(test_char);
end;
/


やっぱりsqlplusで↑をそのままコピって貼り付けると実行できる。
結果は同じで、「TEST」って出るだけであるが、
「test_char」という変数を指定してその中身を表示している点が最初のやり方と違う。

変数定義は[変数名] [変数の型]の順に記述する(Javaと逆だね)。
「test_char char(10)」なら変数名がtest_char、変数の型がchar型の桁数10。
ちなみに桁数指定しないと怒られる。

この例では変数定義と同時に値を代入している。
値の代入には「:=」を使う。
値の代入はbegin以降でも可能だがdeclare部で変数定義してないと怒られる。

begin
    test_char := 'TEST';
end;
/



これは怒られる。「test_char」という変数を定義していないため。

declare
    test_char char(10);
begin
    test_char := 'TEST';
end;
/


↑これならOK。




(3)カーソル定義
SELECTの内容(実行結果)を変数化するイメージ。
SELECT実行して実行結果が尽きるまでぐるぐる回しながら処理、みたいのに使う。
一緒にROWTYPEの変数を定義しておくことが多い。
カーソルはcursor+カーソル名+isで定義することになる。
ROWTYPE変数はカーソル名%ROWTYPEで型指定になる。

declare
    cursor cursor_test is
    select N'TEST' TEST_CHAR from dual
    ;
    row_test cursor_test%ROWTYPE;
begin
…(省略)…
end;
/



カーソルはSELECT実行結果をあらわす「表」全体、
ROWTYPEはSELECT実行結果の1行1行、というかんじ。

あと、カーソル定義には引数(変数)が使える。

declare
    cursor cursor_test(test_char char) is
    select from TEST_TABLE where TEST_ID = test_char;
begin
…(省略)…
end;


この場合、カーソル側に書いたSELECTの実行に際し、「test_char」というchar型の変数が必要であることを示す。
ここでの変数定義には桁数の記述は不要(っていうか桁数書くと怒られる)
引数として渡した「test_char」はカーソルの中でWHERE句として(⇒「where TEST_ID = test_char」)使われる。




(4)カーソルまわす
ご丁寧?にやる場合、①OPEN⇒②FETCH⇒③EXIT⇒④CLOSEの順にやっていく。

set serveroutput on;

declare
    cursor cursor_test is
    select TEST_ID , TEST_NAME from TEST_TABLE
    ;
    row_test cursor_test%ROWTYPE;
begin
    OPEN cursor_test; -- ←①
    
    loop
        fetch cursor_test into row_test; -- ←②
        exit when cursor_test%NOTFOUND; -- ←③
        
        DBMS_OUTPUT.PUT_LINE('TEST_ID,TEST_NAME=' || row_test.TEST_ID || ',' || row_test.TEST_NAME);
        
    end loop;
    
    CLOSE cursor_test; -- ←④

end;
/



①OPENでカーソルを「開き」(つまりSELECT実行し)、
②FETCHでSELECT結果から1行を「取り出して」、
③SELECT結果を全部取り出すまでLOOPし(取り出し切ったらLOOPをEXITで抜ける)、
④開いたカーソルを「閉じる」

ループの中では、ROWTYPEの変数「row_test」の項目「TEST_ID」「TEST_NAME」を取り出して、DBMS_OUTPUTにいれている。

条件句の記述が何もない、単に「LOOP」とだけ書いて始まるループは(↑でかいてるループ)は無限ループになる。
よって、ループの中で、適切な条件でループを「抜ける」(EXITする)記述をしてあげない限り、永久にループから抜けられない。
EXITの後ろにWHEN~で続く部分はその「適切な条件」を指していて、
「cursor_test%NOTFOUND」が「カーソルの中身を全部取り出し切った」を意味している(NOTFOUND=SELECT結果の残り行が見つからない=取り出し切った)。

でももっと簡単な書き方があって

set serveroutput on;

declare

    cursor cursor_test is
    select TEST_ID , TEST_NAME from TEST_TABLE
    ;


begin
    for row_test in cursor_test loop
        DBMS_OUTPUT.PUT_LINE('TEST_ID,TEST_NAME=' || row_test.TEST_ID || ',' || row_test.TEST_NAME);
    end loop;
end;
/



とすれば同じことができる。
↑の赤太字部分が、「OPENして1行ずつ取り出しROWTYPE変数にいれつつ、全て取り出すまでループ」を実現している。
しかも、取り出したSELECT結果を格納するROWTYPEの変数row_testは定義不要
for文の中で初登場でも文句言われることがない。
よってdeclare部でROWTYPE変数をいちいち定義してやる必要がない。
というかこの程度なら

set serveroutput on;

begin
    for row_test in (select TEST_ID , TEST_NAME from TEST_TABLE) loop
        DBMS_OUTPUT.PUT_LINE('TEST_ID,TEST_NAME=' || row_test.TEST_ID || ',' || row_test.TEST_NAME);
    end loop;
end;
/


とすればカーソル定義すら不要である(カーソル変数部分にSELECT文を直に書き込む)
結果的にこの例でいけばdeclareは一切不要になる。
(まあカーソルやROWTYPEだけじゃなくて、
 ワーク用の数値とか、退避用の変数とか、いろいろ欲しくなったりするから、
 やり方に合わせてdeeclareはあってもいいと思うけど)

変数を定義していないと怒る仕様がある一方で、
↑の例みたいに明確な変数定義が不要のまま動かすことができる例もあり、
それらが統一されていないのが若干気持ち悪い、というか、よくわからない。
まあ、こういうもんだとおもうしかないんだろうけどね。