データベース

第4章 リレーショナルデータベース言語SQL
4.1
4.2
4.3
4.4
4.5
4.6
背景と基本概念
データ定義
アクセス権限
問合せ
データ更新
アプリケーションからのデータ操作
4.6 アプリケーションからのデータ操作
■ホスト言語方式
アプリケーションプログラムの中から使用
する方法。標準的には、埋込みSQLが用いら
れる(他の方法もある)。
■埋込みSQL
SQL文そのものの意味は直接起動と同等。
1. ホスト言語方式の課題
(a)ホスト言語中のSQL記述の明確化
(b)SQLとアプリケーションとのデータ受け渡し
(c)SQLの実行時エラー通知
(a) ホスト言語中のSQL記述の明確化
SQL記述はホスト言語の文法にはないので、
構文エラーになる。
A.プリプロセッサで記述
を分離して、関数呼び
出しを生成
(C言語でのSQL)
EXEC SQL SQL記述;
B.特殊な関数を作成する
(Microsoft Access)
システムごとに
記述が異なりがち
(b) SQLからアプリへのデータ受け渡し
マルチ集合に対応するデータ型が
通常のホスト言語にない。
カーソルの概念の導入
カーソルが表内の1行を指す
(c) SQL実行時エラーの通知
プログラムではエラー時処理を含めて
記述する必要がある。
SQLSTATE
:実行状態(5桁の文字コード)
例:00000 正常終了、01005 警告、02000 データなし
これ以外はエラー
SQLCODE:エラーコード(0~-65535)
例 0:正常,100:データなし,
これ以外はエラーコード
2. カーソル
アクセスの手順
(a)カーソルの定義
(b)カーソルのオープン
(c)1行の処理(繰り返し)
(d)カーソルのクローズ
(a) カーソルの定義
【書き方】(カーソル宣言)
DECLARE カーソル名 CURSOR FOR 問合せ式
カーソルの識別のみ。
問合せ自体は、カーソルのオープンで実行。
(b) カーソルのオープン
【書き方】
OPEN カーソル名
①カーソル名で識別された問合せ式の実行。
②問合せ式実行で得られた導出表を作業表という。
③オープン直後カーソルは先頭行に位置づけられる。
④ORDER BY句が指定されていないとき処理系の定義
による順序となる(順序不定)。
(c) 1行処理
(1)1行取出し(FETCH)
【書き方】
FETCH [[<取出し方向>] FROM ]カーソル名
INTO パラメータ名 [[INDICATOR 指標パラメータ名]
[,パラメータ名 [[INDICATOR 指標パラメータ名]・・・]
<取出し方向>で指定される1行の各列の値がINTO句で指定され
る各パラメータに代入される。省略したらNEXT。
行が存在しなければ、SQLSTATEにデータが存在しないことが
報告される。
取出し方向
① NEXT
: カーソルを次の行に移動して、その行を取
り出す。
② PRIOR
: 現在位置の1つ前の行を取り出す。
③ FIRST
: 現在位置に関係なく最初の行。
④ LAST
: 現在位置に関係なく最後の行。
⑤ ABSOLUTE
n : 現在位置に関係なく n 番目の行。
⑥ RELATIVE
n : 現在位置から相対的に n 番目の行。n が負
の場合、前方に数える。
パラメータ名
① プログラム内のデータ領域名を使う。
② 作業表の列数と同じ数でなければならない。
③ 列の順番とパラメータの順番は一致していなければならな
い。
④ パラメータが空値である可能性がある場合、INDICATOR 指
標パラメータを指定しなければならない。
INDICATOR指標パラメータ名
① プログラム内のデータ領域名を使う。
② 空値のとき"-1"、空値でなければ"0"が設定される。
(2)1行の変更(UPDATE)
【書き方】
UPDATE 表名 SET 列名 = 値式, [列名 = 値式, ・・・]
WHERE CURRENT OF カーソル名
① 表名はカーソル定義中の問合せ指定の FROM 句で指定され
ている表名と同じでなければならない。
② 値式として関数を指定することはできない。
③ 値式の代わりにNULLを指定することができる。
④ 更新されるのは作業表のポインタの現在位置に対応する行
であり、そのような行がなければこの文は無効(更新され
るのは、表の対応する行であり作業表ではない)。
⑤ 参照するカーソルは読込み専用であってはならない。
読込み専用のカーソルとは
① ORDER BY 句を含む
② 列名以外を含む値式を含む。
③ 列名が重複している。
④ FROM句に2つ以上の表を含む。
⑤ WHERE句が副問合せを含む。
⑥ GROUP BY句を含む。
(3)1行の削除(DELETE)
【書き方】
DELETE FROM 表名
WHERE CURRENT OF カーソル名
① 表名はカーソル定義中の問合せ指定の FROM 句で指定され
ている表名と同じでなければならない。
② 削除されるのは作業表のポインタの現在位置に対応する行
であり、そのような行がなければこの文は無効(削除され
るのは、表の対応する行であり作業表ではない)。
③ 参照するカーソルは読込み専用であってはならない。
(前シート参照)
(4)カーソルのクロース(CLOSE)
【書き方】
CLOSE カーソル名
この指定で作業表が閉じられる。
【例1】年収が多い順
(以下、擬似コード)
DECLARE 年収順社員作業表 CURSOR FOR
SELECT * FROM 社員 ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表 INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name,incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
DECLARE
(以下、擬似コード)
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
社員
(年収順社員作業表はこの時点で
は作成されない)
社員ID
氏名
年収
課ID
1001
浅田克郎
800
D
1002
佐藤史郎
600
D
1003
田中吉彦
900
S
1004
中原圭吾
800
S
1005
羽田康子
700
S
1006
山田悦子
500
NULL
OPEN
(以下、擬似コード)
社員
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
社員ID
氏名
年収
課ID
1001
浅田克郎
800
D
1002
佐藤史郎
600
D
1003
田中吉彦
900
S
1004
中原圭吾
800
S
1005
羽田康子
700
S
1006
山田悦子
500
NULL
年収順社員作業表
社員ID
氏名
年収
課ID
1003
田中吉彦
900
S
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
(以下、擬似コード)
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
FETCH
PRINT
年収順社員作業表
社員ID
氏名
年収
課ID
1003
田中吉彦
900
S
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
(以下、擬似コード)
Print
Print
1003,田中吉彦,900,D
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
年収順社員作業表
社員ID
氏名
年収
課ID
1003
田中吉彦
900
D
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
(以下、擬似コード)
Print
Print
1003,田中吉彦,900,D
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
年収順社員作業表
偽
社員ID
氏名
年収
課ID
1003
田中吉彦
900
D
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
(以下、擬似コード)
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
FETCH
PRINT
1003, 田中吉彦, 900, D
1001, 浅田克郎, 800, D
年収順社員作業表
社員ID
氏名
年収
課ID
1003
田中吉彦
900
S
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
(以下、擬似コード)
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
Print
Print
1003, 田中吉彦, 900, D
1001, 浅田克郎, 800,D
年収順社員作業表
社員ID
氏名
年収
課ID
1003
田中吉彦
900
D
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
(以下、擬似コード)
DECLARE 年収順社員作業表
CURSOR FOR
SELECT * FROM 社員
ORDER BY 年収 DESC
OPEN 年収順社員作業表
repeat
FETCH 年収順社員作業表
INTO cid, name, incom,
sid INDICATER i-sid
Print cid, name, incom, sid
until (SQLSTATE<>"00000")
CLOSE 年収順社員作業表
(以下省略)
Print
Print
1003, 田中吉彦, 900, D
1001, 浅田克郎, 800,D
年収順社員作業表
偽
社員ID
氏名
年収
課ID
1003
田中吉彦
900
D
1001
浅田克郎
800
D
1004
中原圭吾
800
S
1005
羽田康子
700
S
1002
佐藤史郎
600
D
1006
山田悦子
500
NULL
【例2】年収900万を削除、他、年収1割アップ
(以下、擬似コード)
DECLARE 社員作業表 CURSOR FOR
SELECT * FROM 社員
OPEN 社員作業表
repeat
FETCH 社員作業表 INTO cid, name, incom,
sid INDICATER i-sid
if(incom>=900) then
DELETE FROM 社員
WHERE CURRENT OF 社員作業表
else
UPDATE 社員
SET 年収=年収*1.1
WHERE CURRENT OF 社員作業表
end if
until (SQLSTATE<>"00000")
CLOSE 社員作業表
C言語組込みSQLの例
main() {
EXEC SQL BEGIN DECLARE SECTION;
char SQLSTATE[6]; /* SQL実行結果 */
int incom ;
/* 年収 */
EXEC SQL emp_Cur CURSOR FOR SELECT 年収 FROM 社員;
EXEC SQL OPEN emp_Cur;
EXEC SQL FETCH emp_Cur INTO cid, name, incom,
sid INDICATER i-sid;
while(strcmp(SQLSTATE,"00000")){
if(incom>=900)
EXEC SQL DELETE FROM 社員
WHERE CURRENT OF emp_CUR;
else EXEC SQL UPDATE 社員 SET 年収=年収*1.1
WHERE CURRENT OF emp_CUR;
EXEC SQL FETCH emp_Cur INTO cid, name, incom,
sid INDICATER i-sid;
}
CLOSE emp_Cur;
}