部 | 無名ブロック | 名前つきブロック |
---|---|---|
ヘッダ部 | DECLARE | CREATE OR RELPLACE PROCEDURE 名前 is |
宣言部 | 宣言セクション | 宣言セクション |
実行部 | BEGIN 実行可能セクション |
BEGIN 実行可能セクション |
例外処理部 | EXCEPTION 例外処理セクション END; / |
EXCEPTION 例外処理セクション END; / |
DECLARE ではじまる PL/SQL ブロックは無名ブロックと呼ばれ、毎回コンパイルされます。
DECLARE の代わりに CREATE OR RELPLACE PROCEDURE プロシージャ名 is とすれば、
ストアードプロシージャにできます。
またCREATE OR RELPLACE FUNCTION 関数名 is とすれば、ストアード関数となります。
ストアードプロシージャとストアード関数をまとめてサブプログラムと呼びます。 いずれもヘッダ部と実行部は必須です。
![]() |
![]() |
識別子は、定数、変数、例外、プロシージャ、カーソルなどの PL/SQL オブジェクトの名前です。 識別子には以下の条件があります。
PL/SQL の予約語は以下のとおりです。
ABORT ACCEPT ACCESS ADD ALL ALTER AND ANY ARRAY ARRAYLEN AS ASC ASSERT ASSIGN AT AUDIT AUTHORIZATION AVG BASE_TAVBLE BEGIN BETWEEN BINARY_INTEGER BODY BOOLEAN BY CASE CHAR CHAR_BASE CHECK CLOASE CLUSTER CLUSTERSCOLAUTH COLUMN COLMNS COMMENT COMMIT COMPRESS CONNECT CONSTANT CRASH CREATE CURRENT CURRVAL CURSOR DATABASE DATA_BASE DATE DBA DEBUGOFF DEBUGON DECIMALDECLARE DEFAULT DEFINITION DELAY DELETE DELTA DESC DIFGITS DISPOSE DISTINCT DO DROP ELSE ELSIF END ENTRY EXCEPTION EXCEPTION_INIT EXISTS EXIT FALSE FETCH FILE FLOAT FOR FORM FROM FUNCTION GENERIC GOTO GRANT GROUP HAVING IDENTIFIED IF IMMEDIATE IN INCREMENT INDEX INDEXES INDICATORINITIAL INSERT INETERFACE INTEGER INTERSECT INTO IS LEVEL LIKE LIMITED LOCK LONG LOOP MAX MAXEXTENTS MIN MINUS MLSLABEL MOD MODE MODIFY NATURAL NATURALN NEW NEXTVAL NOAUDIT NOCOMPRESS NOT NOWAIT NULL NUMBER NUMBER_BASE OF OFFLINE ON ONLINE OPEN OPTION OR ORDER OTHERS OUT PACKAGE PARTITION PCTFREE PLS_INTEGER POSITIVE PRAGMA PRIOR PRIVATE PRIVILEGES PROCEDURE PUBLIC RAW RAISE RANGE REAL RECORD REF RELEASE REMR RENAME RESOURCE RETURN REVERSE REVOKE ROLLBACK ROW ROWID ROWLABEL ROWNUMROWS ROWTYPE RUN SAVEPOINT SCHEMA SELECT SEPARATE SET SHARE SIZE SMALLINT SPACE SQL SQLCODE SQLERRM START STATEMENT STDDEV SUBTYPE SUCCESSFUL SUM SYNONYM SYSDATE TABAUTH TABLE TABLES TASK TERMINATE THEN TO TRIGGER TRUE TYPE UID UNION NUNIQUE UPDATE USE USER VALIDATE VALUES VARCHAR VARCHAR2 VARIANCE VIEW VIEWS WHEN WHENEVER WHERE WHILE WITH WORK WRITE XOR
![]() |
![]() |
実行文の書き方はつぎのとおりです。
文種類 | 書式 | 例 |
---|---|---|
コメント | -- コメント rem コメント /* ....... */ |
-- this is a comment rem コメント /* コメント */ |
選択文 | if (式) then 文; end if; |
declare i PLS_INTEGER := 1; MAX_LOOP PLS_INTEGER := 99; begin if i >= MAX_LOOP then dbms_output.put_line('False !' || i); else dbms_output.put_line('True !' || i); end if; end; |
if (式) then 文; else 文; end if; |
||
if (式) then 文; elsif (式) then 文; else 文; end if; |
if deleting then dbms_output.put_line('delete ' || :old.ename ); elsif inserting then dbms_output.put_line('inert ' || :old.ename ); else dbms_output.put_line('update fr:' || :old.ename || ' to:' || :new.ename); end if; |
|
case 選択肢 when 値 then 文; : else 文; end case; |
create or replace procedure getdept is begin declare type cur_type is ref cursor return emp%ROWTYPE; dept_cur cur_type; dept_rec emp%ROWTYPE; i PLS_INTEGER := 1; empno PLS_INTEGER ; begin open dept_cur for select * from emp; loop fetch dept_cur into dept_rec; if dept_cur%NOTFOUND then exit; end if; case dept_rec.deptno when 10 then dbms_output.put_line(dept_rec.empno || ' : ' || dept_rec.ename || ' : ' || dept_rec.deptno); else dbms_output.put_line('Other dept ' || dept_rec.deptno); end case; end loop; close dept_cur; end; end getdept; / | |
繰り返し文 | loop 文; end loop; |
loop if no < MAX_LOOP then prt_no(no); else exit; end if; end loop; |
数値 for ループ変数 in [reverse] MIN .. MAX loop 文; end loop; |
for i in 1 .. MAX_LOOP loop dbms_output.put_line('i=' || i); end_loop; | |
while 条件 loop 文; end loop; |
while (i>MAX_LOOP) loop i := i + 1; dbms_output.put_line('i=' || i); end loop; | |
for カーソル変数 in カーソル名 loop 文 end loop; |
declare cursor sales_cur is select ename,sal,empno from emp where job like 'SALES%'; sales_rec sales_cur%ROWTYPE; begin for sales_rec in sales_cur loop sales_rec.sal := sales_rec.sal * 1.2; end loop; end; | |
制御移行文 | exit [when 論理条件]; | LOOP を終了 |
return 式; | 式値が返される | |
null; | なにも処理しない。例外内で書くことが多い | |
例外ハンドラ | 名前つきシステム例外 | invalid_cursor,value_error,no_data_found |
名前つきプログラマ例外 | ||
名前なしシステム例外 | ||
名前なしプログラマ例外 | if no_faults > MAX_FAULTS then raise too_many_faults; end if; exception when too_many_faults then dbms_output.put_line('Too manay errors !!'); exit; end; | |
raise [例外名]; | 例外を起こす create or replace function b_name (name_in IN VARCHAR2,sex_in IN VARCHAR2) return VARCHAR2 is begin declare name_out VARCHAR2(100) := ''; begin if sex_in = 'M' then name_out := 'Mr. ' || name_in; elsif sex_in = 'F' then name_out := 'Mrs. ' || name_in; else raise value_error; end if; return (name_out); exception when others then raise; end; end; / declare name varchar2(100); begin dbms_output.put_line(b_name('Takahashi','M')); dbms_output.put_line(b_name('Takahashi','F')); dbms_output.put_line(b_name('Takahashi',NULL)); exception when others then dbms_output.put_line(sqlerrm); end; / | |
raise_application_error(エラー番号,エラーメッセージ); エラー番号:-20999〜-20000 |
例外を起こす create or replace function b_name (name_in IN VARCHAR2,sex_in IN VARCHAR2) return VARCHAR2 is begin declare name_out VARCHAR2(100) := ''; begin if sex_in = 'M' then name_out := 'Mr. ' || name_in; elsif sex_in = 'F' then name_out := 'Mrs. ' || name_in; else raise_application_error(-20000,'Invalid parameter'); end if; return (name_out); exception when others then raise; end; end; / declare name varchar2(100); begin dbms_output.put_line(b_name('Takahashi','M')); dbms_output.put_line(b_name('Takahashi','F')); dbms_output.put_line(b_name('Takahashi',NULL)); exception when others then dbms_output.put_line(sqlerrm); end; / | |
データベース 関連 |
select | select ename from emp where empno = 7499; |
insert | insert into emp values (1,'taka','enginer',7222,sysdate,10.0,0,1); | |
update | update emp set sal = sal*1.2 where empno = 7499; | |
commit | commit; | |
rollback | rollback; | |
実行 | コンパイルエラーを知る | show errors |
出力端末に設定 | set serveroutput on; | |
sqlplus から実行 | exec ストアードプロシージャ名; |
![]() |
![]() |
例外ハンドラは、PL/SQL ブロックの実行部で発生している例外だけを処理します。 宣言部や例外処理部で生成された例外は、自動的に外部ブロックに渡されます。
例外は処理された時点で完了し、それ以上は伝播しません。
CREATE OR REPLACE PACKAGE xijdop001 IS E_PROGRAM_ERR EXCEPTION; END xijdop001; / begin raise xijdop001.E_PROGRAM_ERR; dbms_output.put_line('Normal'); exception when xijdop001.E_PROGRAM_ERR then dbms_output.put_line('E_PROGRAM_ERR !!!'); when others then dbms_output.put_line('Other exception !'); end; /
上記を except.sql に書いて実行すると以下のようになります。
SQL> @except パッケージが作成されました。 E_PROGRAM_ERR !!! PL/SQLプロシージャが正常に完了しました。
エラー番号 | 名前つき例外 | エラー番号 | 名前つき例外 |
---|---|---|---|
ORA-00001 | DUP_VAL_ON_INDEX | ORA-00051 | TIMEOUT_ON_RESOURCE |
ORA-00061 | TRANSACTION_BACKED_OUT | ORA-01001 | INVALID_CURSOR |
ORA-01012 | NOT_LOGGED_ON | ORA-01017 | LOGIN_DENIED |
ORA-01403 | NO_DATA_FOUND | ORA-01410 | SYS_INVALID_ROWID |
ORA-01422 | TOO_MANY_ROWS | ORA-01476 | ZERO_DIVIDE |
ORA-01725 | USERENV_COMMMITSCN_ERROR | ORA-01722 | INVALID_NUMBER |
ORA-06500 | STORAGE_ERROR | ORA-06501 | PROGRAM_ERROR |
ORA-06502 | VALUE_ERROR | ORA-06504 | ROWTYPE_MISMATCH |
ORA-06511 | CURSOR_ALREADY_OPEN | ORA-06530 | ACCESS_INTO_NULL |
ORA-06531 | COLLECTIOMN_IS_NULL | ORA-06532 | SUBSCRIPT_OUTSIDE_LIMIT |
ORA-06533 | SUBSCRIPT_BEYOND_COUNT | ORA-09592 | CASE_NOT_FOUND |
ORA-30625 | SELF_IS_NULL | ORA-29280 | INVALID_PATH |
ORA-29281 | INVALID_MODE | ORA-29282 | INVALID_FILEHANDLE |
ORA-29283 | INVALID_OPERATION | ORA-29284 | READ_ERROR |
ORA-29285 | WRITE_ERROR | ORA-29286 | INTERNAL_ERROR |
ORA-29287 | INVALID_MAXLINESIZE | ORA-29288 | INVALID_FILENAME |
ORA-29289 | ACCESS_DENIED | ORA-29290 | INVALID_OFFSET |
ORA-29291 | DELETE_DFAILED | ORA-29292 | RENAME_FAILED |
![]() |
![]() |
変数のデータ型をまとめます。変数は使うまえに宣言しなければなりません。 また変数を宣言するとき、デフォルト値を設定できます。
変数は CONSTANT として宣言しない限り、プログラムの中で値を変更できます。
%TYPE 宣言属性を使って、ある変数のデータ型に PL/SQL の変数や表の列などのデータ構造体を付与できます。 これをアンカーつき宣言といいます。
項目 | 宣言の形式 | 例 |
---|---|---|
変数の宣言 | 変数名 データ型 [:= 初期値]; | bno BINNARY_INTEGER := 3; |
変数名 データ型 DEFAULT 値; | bno BINNARY_INTEGER DEFAULT 3; | |
定数の宣言 | 定数名 CONSTANT データ型 := 値; | MAX_LOOP CONSTANT BINNARY_INTEGER :=100; |
アンカーつき宣言 | 変数名 データ型%TYPE [:= 初期値]; | total_sal NUMBER(20,2); monthly_sal total_sal%TYPE; |
表属性宣言 | 変数名 表名%ROWTYPE ; | monthly_sal emp%ROWTYPE; |
型のグループ | データ型 | 例 |
数値 | BINNARY_INTEGER,PLS_INTEGER | bno BINNARY_INTEGER := 3; |
FLOAT | fno FLOAT; | |
NUMBER[(P,S)] P:精度 S:スケール | no NUMBER(10,3); | |
文字 | CHAR(L) L:文字列最大長 | name CHAR(8) := 'TARO'; |
VARCHAR2(L) L:文字列最大長 | vname VARCHAR2(128); | |
RAW(L) L:バイト最大長 | bdata RAW(256); | |
真理値 | BOOLEAN TRUE,FALSE,NULL の3値のみをもつ | flag BOOLEAN := TRUE; |
日時 | DATE to_date() で代入、to_char() で表示 | today DATE; |
LOB | BFILE,BLOB,CLOB,NCLOB | clob CLOB; |
![]() |
![]() |
PL/SQL レコードは、フィールドと呼ばれる複数の情報の断片で構成されるデータ構造です。 レコードを使用するには、まずレコードを定義し、その型の変数を宣言します。
レコードには、表に基づくレコード、カーソルに基づくレコード、プログラマ定義の3つがあります。
参照 | レコード名.フィールド名 | |
---|---|---|
作成 | 表に基づくレコード | レコード名 表名%ROWTYPE; |
カーソルに基づくレコード | レコード名 カーソル名%ROWTYPE; | |
ユーザ定義のレコード | TYPE 型名 IS RECORD ( フィールド名 データ型, : ); |
![]() |
![]() |
データベース内の構造をあらわす複合型もデータ構造です。
TYPE の定義 | TYPE 型名 IS TABLE OF データ型 [NOT NULL] INDEX BY BINARY_INTEGER; |
---|---|
作成 | create table lob_tbl ( c1 LONG; c2 NUMBER; ); |
ファンクション プロシージャ | 説明 | 例 |
---|---|---|
COUNT | 要素数を返す | emp.COUNT |
DELETE | 行を削除する | emp.DELETE emp.DELETE(4) |
EXISTS | インデックスが定義されているか? | emp.EXISTS |
FIRST | インデックスの最小値 | emp.FIRST |
LAST | インデックスの最大値 | emp.LAST |
NEXT | 次インデックスを返す | emp.NEXT |
PRIOR | 前インデックスを返す | emp.PRIOR |
例 | t_tbl.sql declare type a_table is table of varchar2(10) index by binary_integer; v_table a_table; i pls_integer ; S_LOOP pls_integer := 1; MAX_LOOP pls_integer := 5; begin dbms_output.put_line(' -- v_table datas --'); for i in S_LOOP .. MAX_LOOP loop v_table(i) := 'Takano' || i; dbms_output.put_line(i || '=' || v_table(i)); end loop; v_table.delete(5,16); dbms_output.put_line(' -- v_table datas : after update --'); for i in S_LOOP .. MAX_LOOP loop dbms_output.put_line(i || '=' || v_table(i)); end loop; end; / |
![]() |
![]() |
PL/SQL では NULL 値は変数が値をもっていないことを示します。NULL 値は直接比較することはできません。 専用の関数を使います。
関数構文 | 例 | 変数 IS NULL 変数 IS NOT NULL |
if up_date IS NULL then dbms_output.put_line('更新日が入っていません'); end if; |
---|---|
NVL(p1,p2) p1 が NULL なら p2 を返す | myValue := NVL(yourValue,'DEFAULT'); |
構文 | 例 |
---|---|
create type 変数配列名 as varray(上限) of 型名; | create type a_varray as varray(10) of number; |
表の中に変数配列を作成する | create table a_table (col1 number, col2 a_varray); |
変数配列に値を入れる | declare MAX_LOOP pls_integer := 10; va_array v_arry; begin for i in 1 .. MAX_LOOP loop va_varry(i) := i; end_loop; end; |
変数配列に使用できるメソッドは次のとおりです。
メソッド名 | 機能 | 例 |
---|---|---|
exists | 要素が定義されていれば true,そうでなければ false | |
count | 配列要素数を返す。定義したときは0です | |
limit | 仮想配列の指定された上限を返す | |
first | 変数配列のはじめの要素番号を返す。要素が未定義の場合は NULL を返す | |
last | 変数配列の最後の要素番号を返す。要素が未定義の場合は NULL を返す | |
prior | 指定した要素番号より1つ小さい要素番号を返す | |
next | 指定した要素番号より1つ大きい要素番号を返す | |
delete | 変数配列の要素を削除する | |
extend | 変数配列の終わりに新しいプレースホルダーを作成する | |
trim | 変数配列の終わりから要素を削除する |
![]() |
![]() |
PL/SQL では、任意の宣言部の中で、同じ名前で引数の型や個数が異なる複数のプログラムを定義できます。
これをオーバーロードといいます。ただしなんらかの違いがなければなりません。
次の場合はオーバーロードできません。
関数やプロシージャを宣言するときは、その引数のモードを指定します。
モード | 説明 | 使い方 |
---|---|---|
IN | 入力 | モジュールから参照のみ |
OUT | 出力 | モジュールから値設定のみ |
IN OUT | 入出力 | モジュールから参照、変更ができる |
IN/IN OUT パラメータにはデフォルト値を設定できます。
関数やプロシージャはデータディクショナリに格納されます。
構文 | 例 |
---|---|
drop procedure プロシージャ名; | drop procedure t_for; |
drop function 関数名; | drop function t_for; |
drop tigger トリガー名; | drop trigger updemp; |
パッケージ名.関数名 パッケージ名.プロシージャ名
同じ名前で引数が異なるサブプログラムを複数書くことができます。
![]() |
![]() |
ヘッダ PL/SQL | create or replace function 関数名 [(argument {IN|OUT} type )] return 型; / | create or replace function func1 (id INTEGER, amount REAL) return INTEGER; / |
---|---|---|
ヘッダ c | create or replace function 関数名 [(argument {IN|OUT} type )] return 型 is external name 関数名 library ライブラリ名 parameters (....) language c; / | function func1 (vardata In OUT VARCHAR2) return VARCHAR2 is external name "updvar" library upd_lib parameters(vardata STRING,vardata MAXLEN SB4,return STRING) language c; / |
本体 | function 関数名 [(argument {IN|OUT} type )] return 型 is begin 関数本体 end 関数名; / | function func1 (id INTEGER, amount REAL) return INTEGER is work_var REAL; BEGIN EXCEPTION exception handler END func1; / |
例 |
tst_func2.sql declare name varchar2(100); begin dbms_output.put_line(b_name('Takahashi','M')); dbms_output.put_line(b_name('Takahashi','F')); exception when others then dbms_output.put_line(sqlerrm); end; / |
![]() |
![]() |
ヘッダ PL/SQL | create or replace procedure プロシージャ名 [(argument {IN|OUT} type )] ; / | create or replace procedure proc1 (id INTEGER, amount REAL) ; / |
---|---|---|
ヘッダ c | create or replace procedure 関数名 [(argument {IN|OUT} type )] is external name 関数名 library ライブラリ名 parameters (....) language c; / | procedure func1 (vardata In OUT VARCHAR2) is external name "updvar" library upd_lib parameters(vardata STRING,vardata MAXLEN SB4,return STRING) language c; / |
本体 | procedure プロシージャ名 [(argument {IN|OUT} type )] is begin プロシージャ本体 end プロシージャ名; / | procedure proc1 (id INTEGER, amount REAL) is work_var REAL; BEGIN EXCEPTION exception handler END proc1 / |
例 | create or replace procedure get1 is begin declare cursor sales_cur is select ename,sal,empno from emp where job like 'SALES%'; sales_rec sales_cur%ROWTYPE; i PLS_INTEGER := 1; empno PLS_INTEGER ; begin open sales_cur; loop fetch sales_cur into sales_rec; if sales_cur%NOTFOUND then exit; end if; sales_rec.sal := sales_rec.sal * 1.2; empno := sales_rec.empno; update emp set sal = sales_rec.sal where empno = sales_rec.empno; dbms_output.put_line('count=' || i || ' empno=' || empno || 'emp=' || sales_rec.ename); i := i + 1; end loop; close sales_cur; end; end get1; / |
![]() |
![]() |
パッケージ仕様は必須で、パッケージ外からでも参照できるように公開します。
パッケージ本体には、仕様に含まれるプロシージャ、関数、カーソルなどを実装するすべてのコードが含まれます。
パッケージ仕様 | CREATE OR REPLACE PACKAGE パッケージ名 IS 変数と型の宣言 カーソル仕様 モジュール仕様 END パッケージ名; | create or replace package getrefpkg is procedure prtdata ( cnt IN number, emono IN number, ename IN varchar2, sal IN number); procedure getref; end getrefpkg; / |
---|---|---|
パッケージ本体 | CREATE OR REPLACE PACKAGE BODY パッケージ名 IS 変数と型の宣言 カーソル仕様と SELECT 文 モジュール仕様と本体 BEGIN : END パッケージ名; | create or replace package body getrefpkg is procedure prtdata ( cnt IN number, empno IN number, ename IN varchar2, sal IN number) is begin dbms_output.put_line('count=' || cnt || ' empno=' || empno || ' salary=' || sal || ' emp=' || ename); end prtdata; procedure getrefpk is begin declare type cur_type is ref cursor return emp%ROWTYPE; sales_cur cur_type; sales_rec emp%ROWTYPE; i PLS_INTEGER := 1; empno PLS_INTEGER ; begin open sales_cur for select * from emp where job like 'SALES%'; loop fetch sales_cur into sales_rec; if sales_cur%NOTFOUND then exit; end if; sales_rec.sal := sales_rec.sal * 1.2; empno := sales_rec.empno; update emp set sal = sales_rec.sal where empno = sales_rec.empno; i := sales_cur%ROWCOUNT ; prtdata(i,empno,sales_rec.ename,sales_rec.sal); end loop; commit; close sales_cur; end; end getrefpk; end getrefpkg; / |
パッケージの実行 | BEGIN パッケージ名.プロシージャ名(); END; |
begin getrefpkg.getrefpk(); end; / |
![]() |
![]() |
トリガーは名前つき PL/SQL ブロックである点はプロシージャに似ていますが、 他のブロックから契機となるイベントが発生するたびに暗黙的に実行されます。 トリガーの実行の契機となるイベントには次の3つがあります。
機能 | 構文 | 例 | 確認 |
---|---|---|---|
定義 | create or replace trigger トリガー名 {before|after} トリガーイベント on 表名 [for each row [when トリガー条件] トリガー本体; | create or replace trigger updemp after insert or delete or update on emp for each row declare emprec emp%ROWTYPE; begin if deleting then dbms_output.put_line('delete ' || :old.ename ); elsif inserting then dbms_output.put_line('inert ' || :old.ename ); else dbms_output.put_line('update fr:' || :old.ename || ' to:' || :new.ename); end if; end updemp; / | user_triggers |
削除 | drop tigger トリガー名; alter trigger トリガー名 disable; |
drop trigger updemp; alter trigger updemp disable; |
user_triggers |
例 | create table emp_log ( emp_no NUMBER(4), who varchar2(10), operation char(1)); |
イベント | 説明 |
---|---|
insert | 表またはビューに行が追加されると発行する |
update | 表またはビューの行が変更されると発行する。OF 句で特定の列の更新だけに限定できる |
delete | 表またはビューの行が削除されると発行する |
alter | alter 文でデータベースオブジェクトが変更されると発行する |
drop | drop 文でデータベースからオブジェクトが削除されると発行する |
servererror | サーバのエラーメッセージがログにきろくされると発行する |
logon | 表またはビューに行が追加されると発行する |
logoff | 表またはビューに行が追加されると発行する |
startup | データベースがオープンされると発行する |
shutdown | データベースがクローズされると発行する |
文種 | :old | :new |
---|---|---|
insert | NULL | 該当文実行後の値 |
update | 変更前の値 | 該当文実行後更新した値 |
delete | 実行前の値 | NULL |
述語 | 動作 | |
inserting | トリガーの契機となる文が insert の場合は true そうでない場合は false | |
updating | トリガーの契機となる文が update の場合は true そうでない場合は false | |
deleting | トリガーの契機となる文が delet の場合は true そうでない場合は false |
![]() |
![]() |
演算子 | 説明 | 例 |
---|---|---|
** | 指数 | B := A**2 |
NOT | 論理的否定 | if (NOT b) then str := 'FALSE';end if; |
+,- | 符号 | B := -A; |
*,/ | 乗算、除算 | B := A/2; |
+,- | 加算、減算 | B := A + 10; |
|| | 文字列連結 | STR := 'AAA' || 'BBB'; |
=,!=,<,>,<=,>= | 論理的比較 | if (A = B) then ans := 1; end if; |
AND,OR | 論理積、論理和 | if ((A=B) AND (B!=C)) then str := 'OK'; end if; |
カーソルは、データベース内の表へのポインタと考えられます。 まず宣言してオープンすると使えます。 fetch でポインタをデータベースのレコードに一致させ、要素を取り出せます。 終了後にはクローズします。暗黙のカーソルは SQL です。
宣言 | CURSOR カーソル名 [(引数)] [RETURN 戻り値] is SELECT 文; | cursor emp_cur is select * from emp; |
---|---|---|
open | OPEN カーソル名 [(引数)]; | open emp_cur; |
fetch | FETCH カーソル名 INTO レコード/変数リスト; | fetch emp_cur into emp_rec; |
close | CLOSE カーソル名; | close emp_cur; |
カーソルには以下の4つの属性があります。
名前 | 説明 | 例 |
---|---|---|
%FOUND | レコードが取れると真、失敗すると偽 | SQL%FOUND |
%NOTFOUND | レコードが取れないと真、成功すると偽 | SQL%NOTFOUND |
%ROWCOUNT | その時点までのレコード数を返す | SQL%ROWCOUNT |
%ISOPEN | カーソルがオープンされていると真、そうでないと偽 | SQL%ISOPEN |
例 | if dept_cur%NOTFOUND then exit; end if; |
カーソル変数は、カーソルオブジェクトを参照するデータ構造です。
カーソルオブジェクトとは、カーソルの結果セットを指します。
oracle では SGA の作業領域へのポインタです。
定義 | TYPE カーソル名 IS REF CURSOR [RETURN レコードの型]; RETURN 句を指定しない場合は、弱い型の REF CURSOR を宣言することになります。 弱い型の REF CURSOR は、実行時に任意の問い合わせに関連付けられます。 |
declare type emp_cur is ref cursor return emp%ROWTYPE; emp_rec emp_cur; begin open emp_cur for select * from emp; fetch emp_cur into emp_rec; close emp_cur; end; |
---|---|---|
open | OPEN カーソル変数名 for select 文; | open emp_cur for select * from emp; |
fetch | FETCH カーソル変数名 INTO レコード/変数リスト; | fetch emp_cur into emp_rec; |
close | CLOSE カーソル変数名; | close emp_cur; |
例 | getrefp.sql set serveroutput on; create or replace procedure prtdata ( cnt IN number, empno IN number, ename IN varchar2, sal IN number) is begin dbms_output.put_line('count=' || cnt || ' empno=' || empno || ' salary=' || sal || ' emp=' || ename); end prtdata; / show errors create or replace procedure getrefp is begin declare type cur_type is ref cursor return emp%ROWTYPE; sales_cur cur_type; sales_rec emp%ROWTYPE; i PLS_INTEGER := 1; empno PLS_INTEGER ; begin open sales_cur for select * from emp where job like 'SALES%'; loop fetch sales_cur into sales_rec; if sales_cur%NOTFOUND then exit; end if; sales_rec.sal := sales_rec.sal * 1.2; empno := sales_rec.empno; update emp set sal = sales_rec.sal where empno = sales_rec.empno; i := sales_cur%ROWCOUNT ; prtdata(i,empno,sales_rec.ename,sales_rec.sal); end loop; close sales_cur; end; end getrefp; / |
実行結果 SQL> exec getrefp count=1 empno=7499 salary=3981.31 emp=ALLEN count=2 empno=7521 salary=3110.4 emp=WARD count=3 empno=7654 salary=3110.4 emp=MARTIN count=4 empno=7844 salary=3732.48 emp=TURNE PL/SQLプロシージャが正常に完了しました |
![]() |
![]() |
構文は以下のとおりです。 定義済みの関数である sqlcode と sqlerrm を使うと oracle のエラー番号とエラーメッセージを調べられます。
構文 | 例 |
---|---|
EXCEPTION WHEN 例外 THEN 処理部 WHEN 例外 THEN 処理部 WHEN OTHERS THEN END; | create or replace procedure fio_tst is begin declare config_file utl_file.file_type; FPASS varchar2(20) := 'OUT_DIR'; FNAME varchar2(20) := 'out.log'; iomode varchar2(20) := 'a'; line_in varchar2(128) := 'sample data 1'; begin config_file := utl_file.fopen(FPASS,FNAME,iomode); utl_file.put(config_file,line_in); utl_file.new_line(config_file); utl_file.fclose(config_file); exception when utl_file.invalid_path then dbms_output.put_line(FPASS || FNAME || ': invalid path or name:open '); when utl_file.invalid_mode then dbms_output.put_line(FPASS || FNAME || ': invalid mode :open '); when utl_file.invalid_operation then dbms_output.put_line(FPASS || FNAME || ': invalid ope:open '); when utl_file.write_error then dbms_output.put_line(FPASS || FNAME || ': write error '); when others then dbms_output.put_line(sqlcode || ' : ' || sqlerrm); end; end fio_tst; / |
また例外が発生したとき、その処理後は呼び元に返ります。
set serveroutput on; create or replace package pk_a is procedure proc_a1(arg in varchar2); end; / create or replace package pk_b is procedure proc_b1(argb in varchar2); end; / create or replace package body pk_b is procedure proc_b1(argb in varchar2) is buf number; begin dbms_output.put_line('B : before to_number'); buf := to_number(argb); dbms_output.put_line('B : after to_number'); exception when others then dbms_output.put_line(sqlerrm); end; end; / create or replace package body pk_a is procedure proc_a1(arg in varchar2) is begin dbms_output.put_line('A : before proc_b1'); pk_b.proc_b1(arg); dbms_output.put_line('A : after proc_b1'); end; end; / exec pk_a.proc_a1('123'); exec pk_a.proc_a1('aaa');
実行結果 A : before proc_b1 B : before to_number B : after to_number A : after proc_b1 PL/SQLプロシージャが正常に完了しました。 A : before proc_b1 B : before to_number ORA-06502: PL/SQL: 数値または値のエラー: 文字から数値への変換エラー。が発生しました A : after proc_b1 PL/SQLプロシージャが正常に完了しました。
![]() |
![]() |
構文 | 例 | 参照 |
---|---|---|
データ操作言語(DML) | select,insert,update,delete,set transaction,explain plan | dbms_sql |
データ定義言語(DDL) | drop,create,alter,grant,revoke | |
トランザクション制御 | commit,rollback,savepoint | |
セッション制御 | commit,rollback,savepoint | |
システム制御 | alter system | |
組み込み SQL | connect,declare cursor,allocate |
select | select SELECT_LIST into 変数 from 表 [where 句]; |
---|---|
insert | insert into 表 [(カラム名)] values (値リスト); |
update | update 表 SET (カラム名) SELECT_LIST into 変数 from 表 [where 句]; |
delete | delete from where 句; |
構文 | 例 |
---|---|
execute immediate SQL_STRING using | begin ececute immediate 'drop table emp'; end; / |
open CURSOR_VAR for QUERY_STRING using | |
例 | create or replace procedure runplsql ( progname IN varchar2, inval IN number, outval1 OUT varchar2, outval2 OUT varchar2) is begin execute immediate 'begin ' || progname || '(:val1, :val2, :val3);end;' using inval, OUT outval1, OUT outval2; end; / |
![]() |
![]() |
数値関数 | 説明 | 例 | 結果 |
---|---|---|---|
length(str) | str の長さを返す | length('XYXYXShort') | 10 |
mod(x,y) | x/y の剰余を求める | mod(23,5) | 3 |
文字関数 | 説明 | 例 | 結果 |
lpad(str1,len,[str2]) | str1 の左側を str2 で埋め全体長が len になるようにします | lpad('Short',10,XY) | XYXYXShort |
ltrim(str1,str2) | str1 の左側にある str2 を削除します | ltrim('XYXYXShort',XY) | Short |
replace(str,srh_str,[rep_str]) | str の srh_str を rep_str でおきかえます | replace(This and That','Th','B') | Bis and Bat |
rpad(str1,len,[str2]) | str1 の右側を str2 で埋め全体長が len になるようにします | rpad('Short',10,XY) | ShortXYXYX |
rtrim(str1,str2) | str1 の右側にある str2 を削除します | rtrim('ShortXYXYX',XY) | Short |
substr(str,a,[b]) | str の中の a 以降 b 文字を返します | substr(abc123def,4,4) | 123d |
日付関数 | 説明 | 例 | 結果 |
add_months(day,n) | day に n 日を足した日付を返す | add_months('02-FEB-91',1) | 02-MAR-92 |
last_day(day) | day の月の最終日を返す | last_day('02-FEB-91') | 28-FEB-91 |
months_between(day1,day2) | day1 と day2 の間の月数を返す | months_between('02-FEB-91','02-FEB-90') | 12 |
next_day(date,day) | date の次の day を返す | next_day('02-FEB-91','friday') | 8-FEB-91 |
trunc(date[,format]) | date を format 書式で返す | trunc(sysdate,'YYYY MM DD') | 2005 12 19 |
to_char(date[,format]) | date を varchar2 文字列で返す | to_char(sysdate) | 2005 年12 月 19 日 |
その他関数 | 説明 | 例 | 結果 |
nvl(exp1,exp2) | exp1 が NULL の場合は exp2 を返す | nvl(NULL,'OK') | OK |
![]() |
![]() |
dbms_job | 説明 | 例 |
---|---|---|
broken | 指定したジョブに中断マークをつける。以降実行されない | |
interval | キューに登録されたジョブの実行間隔を変更する | |
isubmit | 指定したジョブ番号を持つキューにジョブを投入する | |
remove | ジョブをキューから削除する | |
run | 指定したジョブの即時実行を強制する | |
submit | ジョブをキューに送り、そのジョブ番号を返す | |
dbms_sql | 説明 | 例 |
bind_variable | 特定の値をホスト変数にバインドする | |
close_cursor | カーソルをクローズする | |
column_value | カーソルからローカル変数に値を取り出す | |
define_column | カーソルをクローズする | |
execute 関数 | カーソルを実行する | |
fetch_rows 関数 | カーソルから行を取り出す | |
is_open 関数 | カーソルがオープンされているとき真を戻す | |
open_cursor 関数 | カーソルをオープンする | |
parse プロシージャ | 指定された SQL 文を構文解析する | |
variable_value | カーソル内の変数値を取得する | |
dbms_output | 説明 | 例 |
初期設定 | set serveroutput on; 端末に出力する | |
disable | dbms_output バッファを画面にフラッシュさせない | |
enable | dbms_output バッファを画面にフラッシュさせる | |
get_line | dbms_output バッファから1行を受け取る | |
get_lines | dbms_output バッファから複数行を受け取り PL/SQL 表に渡す | |
new_line | dbms_output バッファに改行を挿入する | |
put | dbms_output バッファに情報を書き込む | |
put_line | dbms_output バッファに情報を書き込み改行を追加する | |
utl_file | 説明 | 例 |
前処理 1 | SQL> CREATE DIRECTORY OUT_DIR AS '/tmp/taka2'; SQL> GRANT READ ON DIRECTORY OUT_DIR TO DBA; select * from all_directories; これで登録できたことを確認 以降このディレクトリ名 (OUT_DIR) を使う | |
前処理 2 | init.ora の utl_file_dir=* を入れるとパーミッションが無効化されます | |
fclose | 指定ファイルをクローズする | fclose(UTL_FILE.FILE_TYPE) |
fclose_all | オープンした全ファイルをクローズする | fclose_all |
fflush | 全データをファイルに書き出す | fflush(FILE_TYPE) |
fopen | 指定ファイルをオープンする | UTL_FILE.FILE_TYPE=fopen(pass,name,mode) |
get_line | ファイルから次行を取り出す | get_line(UTL_FILE.FILE_TYPE,buf) |
is_open | ファイルがすでにオープンされている場合、真を返す | bool=is_open(UTL_FILE.FILE_TYPE) |
new_line | 現在行に改行マークを入れる | new_line(UTL_FILE.FILE_TYPE,nline) |
put | テキストをバッファに書き込む | put(UTL_FILE.FILE_TYPE,line) |
put_line | 1行分のテキストをファイルに書き込む | put_line(UTL_FILE.FILE_TYPE,line) |
putf | 書式化されたテキストをバッファに書き込む | putf(UTL_FILE.FILE_TYPE,fmt,item_lst) |
例1 | declare config_file utl_file.file_type; FPASS varchar2 := 'OUT_DIR'; FNAME varchar2 := 'out.log'; MODE varchar2 := 'A'; begin config_file := utl_file.fopen(FPASS,FNAME,MODE); utl_file.put(config_file,line_in); utl_file.new_line(config_file); utl_file.fclose(config_file); exception when utl_file.invalid_path then dbms_output.put_line(FPASS || FNAME || ' invalid pass '); when utl_file.invalid_mode then dbms_output.put_line(FPASS || FNAME || ' invalid mode '); when utl_file.write_error then dbms_output.put_line(FPASS || FNAME || ' do not to wtite '); when others then dbms_output.put_line(FPASS || FNAME || ' other error '); end; / | |
例2 |
fred.sql create or replace procedure fread is begin declare config_file utl_file.file_type; FPASS varchar2(20) := '/tmp/taka2/'; FPASS5 varchar2(20) := 'OUT_DIR'; FNAME varchar2(20) := 'jpn.data'; iomode varchar2(20) := 'r'; line_in varchar2(128) ; begin config_file := utl_file.fopen(FPASS5,FNAME,iomode); utl_file.get_line(config_file,line_in); dbms_output.put_line(line_in); utl_file.fclose(config_file); exception when utl_file.invalid_path then dbms_output.put_line(FPASS || FNAME || ': invalid path or name:open '); when utl_file.invalid_mode then dbms_output.put_line(FPASS || FNAME || ': invalid mode :open '); when utl_file.invalid_operation then dbms_output.put_line(FPASS || FNAME || ': invalid ope:open '); when utl_file.write_error then dbms_output.put_line(FPASS || FNAME || ': write error '); when others then dbms_output.put_line(FPASS || FNAME || ': other error '); end; end fread; / | |
dbms_utilty | 説明 | 例 |
format_call_stack | call stack を varchar2 値として返す | cstk := dbms_utility.format_call_stack; |
![]() |
![]() |
debug.sql に debug/reset があります。 debug_tbl に情報がはいります。
create or replace package debug is -- select debug_str from debug_tbl order by lineno; procedure debug(i_desc in varchar2,value in varchar2); procedure reset; end debug; / show errors create or replace package body debug is lno NUMBER; procedure debug(i_desc in varchar2,value in varchar2) is begin insert into debug_tbl(debug_str,lineno) values (i_desc || '* '|| value,lno); commit; lno := lno + 1; end debug; procedure reset is begin lno := 1; delete from debug_tbl; end reset; begin reset; end debug; / show errors
![]() |
![]() |
PL/SQL でかけない部分を c や java で書き、それらを呼び出す手段として外部プロシージャがあります。 PL/SQL からの呼び出し方について説明します。
外部プロシージャをよびだすためには、外部プロシージャ専用のリスナーを起動し tnsnames.ora に記述する 必要があります。それらについては外部プロシージャコールを参照してください。
構文 | 例 |
---|---|
create or replace library ライブラリID is'フルパス名'; create or replace function PL/SQL 関数名 [(引数名 IN/OUT 型名)] return 型名 is external name "c プログラムの関数名" library ライブラリID parameters (変数名 型名, ... ,return 型名) languae [c,java]; / | set serveroutput on; create or replace library upd_lib as '/tmp/update.so'; / create or replace function updvar (vardata IN OUT VARCHAR2) return VARCHAR2 is external name "updvar" library upd_lib parameters (vardata STRING,vardata MAXLEN SB4,return STRING) language c; / show errors create or replace procedure gg is vardata VARCHAR2(32767); retdata VARCHAR2(32767); no PLS_INTEGER ; i PLS_INTEGER ; MAX_LOOP PLS_INTEGER := 4; begin i := 0; while i<MAX_LOOP loop select c1,c2 into vardata,no from vartbl where c2 = i; dbms_output.put_line('before : no='||no ||' vardata='||vardata); retdata := updvar(vardata); dbms_output.put_line('after : no='||no ||' vardata='||vardata); dbms_output.put_line('return : no='||no ||' retdata='||retdata); update vartbl set c1 = retdata where c2 = i; i := i+1; end loop; commit; end gg; / show errors |
開発手順
#include <stdio.h> char *prt(void); char msg[]="Hello World !!"; char *prt() { return msg; }
cc -G prt.c -o libprt.so cp libprt.so /tmp
create or replace library prt_lib as '/tmp/libprt.so'; / create or replace function prtfunc return VARCHAR2 is external name "prt" library prt_lib language c; / show errors create or replace procedure prt is begin dbms_output.put_line(prtfunc()); end; /
実行 SQL> exec prt Hello World !! PL/SQLプロシージャが正常に完了しました
![]() |
![]() |
public class hel { static final String msg = "Hello World !!"; public static String prt() { return msg; } } コンパイル > javac hel.java
create or replace function extjava return varchar2 is language java name 'hel.prt() return java.lang.String'; / set serveroutput on size 10000; call dbms_java.set_output(1000); begin dbms_output.put_line(extjava); end; /
実行 SQL> @hel ファンクションが作成されました コールが完了しました Hello World !! PL/SQL プロシージャが正常に完了しました
![]() |
![]() |
エラーメッセージ | 対処法 |
---|---|
ORA-1405: フェッチした列の値がNULLです |
|
ORA-28575: リモートエージェントへの RPC 接続が失われました |
extproc が異常終了し実行不可となったためです。
実行中の外部プロシージャのライブラリが異常終了した場合などにおこります。 その場合は $ORACLE_HOME/rdbms/log 下に core があります。 |
ORA-6525: CHARまたはRAWデータの長さが一致しません |
PL/SQL 側の宣言と外部プロシージャのライブラリ側の宣言が一致していない場合などにおこります |
ORA-28595: Extproc agent : Invalid DLL Path |
oracle9i からセキュリティ強化のため以下を設定する必要があります(ENVS="EXTPROC_DLLS=ANY", ENVS="LD_LIBRARY_PATH=$ORACLE_HOME/lib:外部プロシージャのライブラリの場所")ただし $ORACLE_HOME/lib はフルパスをそのまま記述すること KROWN 13162,14244 参照 |
![]() |
![]() |
課題 | プログラム例 | 実行結果 |
---|---|---|
50 までの 3 で割り切れる数を表示する div3.sql |
declare no PLS_INTEGER; MAX_LOOP CONSTANT PLS_INTEGER := 30; begin for no in 1 .. MAX_LOOP loop if mod(no,3) = 0 then dbms_output.put_line(no); end if; end loop; end; / |
SQL> @div3 3 6 9 12 15 18 21 24 27 30 |
boolean のテスト bool.sql |
declare total_sales NUMBER := 1001; no_revenue BOOLEAN; msg varchar2(12) := 'FALSE'; begin no_revenue := total_sales <= 0; if (no_revenue) then msg := 'TRUE'; end if; dbms_output.put_line(msg); end; / |
SQL> @bool FALSE |
エラーの内容 | 対処法 |
---|---|
endif; と書いた | end if; とする |
仮パラメータに長さや精度、スケールの制約を書いた | 仮パラメータは型だけを指定します |
プロシージャ、関数が見つからない | パッケージ名.プロシージャまたはパッケージ名.関数と書けばよい |
本の題名 | 出版社 | 価格 |
---|---|---|
ORACLE PL/SQL programming 基礎編 | オライリージャパン | 4500 |
ORACLE PL/SQL programming 応用編 | オライリージャパン | 4300 |
ORACLE PL/SQL ワークブック | オライリージャパン | 5800 |
ORACLE PL/SQL プログラミング | 翔泳社 | 5600 |
![]() |
![]() |