ORACLEとSQL Server系の大きな違いとは? ▲TOP
SQL Server系(Sybase, MS)の経験者が初めてORACLEのストアドプロシージャを作った時に、おそらく面食らうであろうと思われるのが『BEGIN~ENDブロック内にSELECT文が書けない』と言う点です。
例えばTransact-SQLやWatcom-SQLでは、
create procedure sp_hogehoge @inum int as
begin
--何かの処理
--その処理結果に基づき変数やテーブルをSELECTする
select * from ksale where empno = @inum
end
と言った書き方が可能です。上記の sp_hogehoge を Access のパススルークエリーから実行する場合、
exec sp_hogehoge 7
とクエリーのSQLに書いておけば単純にテーブルやビューをSELECTした場合と同様にダイナセットを得る事ができ
ます。
しかし、ORACLE では、BEGIN~ENDブロック(PL/SQLブロック)の中に上記のようなSELECT文を書くことができま
せん。INTOを使用した値の代入、カーソル、サブクエリーにのみ使用できます。
そこでストアドを呼び出して複数行の結果を得るためには、PL/SQL表(配列)を使ったり、カーソルをバインドしたりする必要があります。
これをクライアントアプリケーションから実行するとなると、もうODBCではできないので、ミドルウェアにはネイティブなものを選択する必要があります。
(最近のODBCでは、カーソルについては、
API関数を呼ぶ事で実装できるようです)。
逆にORACLEのみをやっている人は、SQL Server系のストアドを初めて作る時に、自前配列を作ったりしないようにしましょう。
END の直前に SELECT文を書けばよいだけなので。
手続き型言語の書き方は?(BEGIN~ENDブロック) ▲TOP
ORACLE MSSQL SSA MySQL
基本的な制御の例を以下に示します。
MySQLの場合、
ORACLEやMSSSQLのように無名のBEGIN~ENDブロックを実行する事はできないようです。
つまり実行するためには必ずストアドプログラムとしてコンパイルする必要があります。
(この認識が勘違いだったら、ご指摘いただけると幸甚であります)
--drop PROCEDURE sp_hoge;
--デリミタを変更しておく
delimiter //
CREATE PROCEDURE sp_hoge()
DETERMINISTIC
BEGIN
/* 変数宣言 */
DECLARE mystr VARCHAR(20);
DECLARE mycnt INTEGER(2);
/* 値の代入 */
SET mycnt = 0;
SET mystr = '文字';
/* IF文 */
IF mycnt = 0 THEN
SET mystr = '文字2';
select mystr;
ELSE
select '文字3';
END IF;
/* CASE文 */
CASE extract(month from now())
WHEN 1 THEN SET mystr = '1月';
WHEN 2 THEN SET mystr = '2月';
WHEN 3 THEN SET mystr = '3月';
WHEN 4 THEN SET mystr = '4月';
ELSE SET mystr = '1~4月以外';
END CASE;
select mystr;
/* WHILE-LOOP */
WHILE mycnt <= 5 DO
SET mycnt = mycnt + 1;
select mycnt;
END WHILE;
/* BEGIN-ENDブロック内でのSELECT文の発行 */
/* PROCEDUREでは可能(FUNCTION内ではできない) */
select * from kemp;
END//
--デリミタをセミコロン(デフォルト)に戻しておく
delimiter ;
--ストアドプロシージャ実行
call sp_hoge();
ストアドプロシージャのサンプル(カーソルを使用するたLOOP処理) ▲TOP
ORACLE MSSQL SSA MySQL
カーソルを使用するLOOP処理のサンプルです。
入力パラメータで指定した部署番号に該当する社員について、
役職が『スタッフ』である場合は、氏名の横に『営業スタッフ:』と表示します。
--drop PROCEDURE sp_hoge;
--デリミタを変更しておく
delimiter //
CREATE PROCEDURE sp_hoge(inum INTEGER(3))
DETERMINISTIC
BEGIN
/* 変数宣言 */
/* カーソル使用時のデータ有無判断に使用 */
DECLARE done INT DEFAULT 0;
/* それ以外の変数 */
DECLARE v_mystr VARCHAR(20);
/* カーソル使用列 */
DECLARE v_empnm VARCHAR(40);
DECLARE v_job VARCHAR(20);
/* カーソル宣言 ※ 他の変数の後に定義する */
DECLARE cur1 CURSOR FOR
select empnm,job from kemp where deptno = inum;
/* データ無し時のLOOP脱出用おまじない */
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
/* カーソルオープン */
OPEN cur1;
/* LOOP */
LOOPPROC:REPEAT
FETCH cur1 INTO v_empnm,v_job;
IF NOT done THEN
IF v_job = 'スタッフ' THEN
SET v_mystr = '営業スタッフ:';
ELSE
SET v_mystr = '';
END IF;
select CONCAT(v_mystr,v_empnm);
/* ↓他の条件でLOOPを脱出したい時はLEAVEで */
/* LEAVE LOOPPROC; */
END IF;
UNTIL done END REPEAT;
/* カーソルクローズ */
CLOSE cur1;
END//
--デリミタをセミコロン(デフォルト)に戻しておく
delimiter ;
--ストアドプロシージャ実行
call sp_hoge(1);