このページでは、静的SQLと動的SQL、ホスト変数、カーソル処理(DECLARE → OPEN → FETCH → CLOSE)、COMMITとROLLBACKがわかります。
- 一言で言うと:
- C言語などのプログラムの中にSQL文を埋め込んでデータベースを使う方法(埋込みSQL、親言語方式)の話
- 1行だけ取るならSELECT…INTO、何行も取るならカーソルを使ってFETCHで1行ずつ取り出す
基本(静的SQLと動的SQL、非カーソル処理、ホスト変数)→ 何行も取り出す(カーソル処理:DECLARE → OPEN → FETCH → CLOSE)→ 確定と取消し(COMMIT、ROLLBACK、WHERE CURRENT OF)
覚え方の軸
- SQLの決まり方は「前から決まっているか、実行中に決まるか」
- 静的SQLは、あらかじめ決まったSQL文を埋め込む
- 動的SQLは、実行中にSQL文を作って実行する
- 取り出す行数で方式が分かれる
- 1行なら、非カーソル処理(SELECT … INTO :ホスト変数)
- 複数行なら、カーソル処理(結果を1つのファイルのように見て、1行ずつ取り出す)
- カーソル処理は「宣言 → 開く → 取り出す(繰返し)→ 閉じる」
- DECLARE CURSOR → OPEN → FETCH → CLOSE
- 取り出す行がなくなると、SQLCODEにNOT FOUNDが入る
- ホスト変数には「:」を付ける
- プログラムとデータベースの受け渡し口。SQL文の中では :name のように書く
埋込みSQLの基本事項(★)
① 静的SQLと動的SQL
- 静的SQL:
- あらかじめ決められたSQL文を、プログラムの中に埋め込んで実行する方式
- 動的SQL:
- 実行するSQL文が、プログラムの実行中でなければ決まらない場合に、SQL文を動的に作成して実行する方式
- 静的SQLと動的SQLの例え:
- 静的SQLは、決まった定型文の注文票
- 動的SQLは、客の希望を聞いてから、その場で注文票を書く
② 非カーソル処理
- 非カーソル処理:
- データベースの表から1行を取り出すこと
- 非カーソル処理の構文:
EXEC SQL SELECT 列名リスト INTO :ホスト変数名リスト
FROM 表名
[WHERE 条件]
- 例:
- 社員表から、社員コードが’101’の社員の社員名と年齢を取り出す
EXEC SQL SELECT 社員名, 年齢 INTO :name, :age FROM 社員
WHERE 社員コード = '101';
- INTO句とホスト変数:
- 埋込みSQLでは、SELECT文の結果を受け取るホスト変数を、INTO句に指定する必要がある
- このとき、ホスト変数の前に必ず「:」を付ける
- SQLプリコンパイラ:
- EXEC SQL文は、そのままでは親言語(C言語など)の文法に違反する
- だから、コンパイラにかける前に、SQLプリコンパイラ(事前コンパイラ)で、データベースアクセス関数の呼出し文に変換する
③ ホスト変数
- ホスト変数:
- データベースとプログラムのインタフェースとなる変数
- ホスト変数の使い方:
- 埋込みSQLでは、SQL文の実行で取り出したデータを、INTO句で指定したホスト変数に入れる
- ホスト変数は通常の変数としてもアクセスできる
- だから、出力関数で表示したり、入力関数で値を入力して、それをSELECT文の条件に使ったりもできる
- ホスト変数の例え:
- データベースとプログラムの間にある「受け渡し用のトレイ」。データベースがトレイに置いたものを、プログラムが取って使う
カーソル処理とFETCH:何行も1行ずつ取り出す(★)
① カーソル処理
- 非カーソル処理の限界:
- 「SELECT…INTO…」の形では、1行のデータしか取り出せない
- カーソル処理:
- 検索の結果が複数行になる場合に使う
- SQL文で問い合わせた結果を、あたかも1つのファイルであるかのようにとらえ、FETCH文でそこから1行ずつ取り出す方式
- 一度に複数行:
- データベースによっては、1回のFETCHで一度に複数行取り出せるものもある
- カーソルの例え:
- 検索結果の一覧表に当てる「しおり」。FETCHするたびに、しおりの行を読んで、しおりを1行下にずらす
カーソル処理の流れ(★)
- カーソルの宣言:
- DECLARE カーソル名 CURSOR FOR SELECT文
- 指定したSELECT文の問合せに、カーソル名を付ける
- カーソルを開く:
- OPEN カーソル名
- SELECT文が実行され、カーソルは実行結果の先頭行を指す(カーソル位置づけ)
- 1行の取り出し:
- FETCH カーソル名 INTO 結果受け取りのホスト変数
- 1行ずつ取り出し、INTO句で指定したホスト変数に入れる。1行取り出した後、カーソルは次の行を指す
- 取り出す行がなくなったときは、SQLCODEにNOT FOUNDコードが設定される
- 取り出したデータを基に処理:
- データの終わりでなければ、3に戻って繰り返す
- カーソルを閉じる:
- データの終わりなら、CLOSE カーソル名で閉じて、カーソル処理を終わる
- SQLCODE:
- SQL文の実行結果のコードが設定される
- 例えば、0は正常終了
- 参考書によっては「負:NOT FOUND又はエラー」と説明していることもある
- 注意(表記の違い):
- SQL標準では、NOT FOUND(取り出す行がない)は正の値の100で、負の値はエラーを表す
- 試験では「0なら正常、0以外ならNOT FOUNDかエラー」と押さえておけば、下のプログラムのように「SQLCODE != 0 で抜ける」という判定が読める
カーソル処理のプログラム例
- やりたいこと:
- 社員表から、住所が福岡で始まる社員の社員名を表示する(取り出す社員名に空値はないものとする)
EXEC SQL DECLARE emp_cur CURSOR FOR
SELECT 社員名 FROM 社員
WHERE 住所 LIKE '福岡%';
EXEC SQL OPEN emp_cur;
while(1){
EXEC SQL FETCH emp_cur INTO :name;
if(SQLCODE != 0) break;
printf("氏名は%s\n", name); }
EXEC SQL CLOSE emp_cur;
- 読み方:
- DECLAREで、「住所が福岡で始まる社員の社員名」を取るSELECT文に、emp_curというカーソル名を付ける
- OPENで、SELECT文を実行する
- whileの中で、FETCHで1行ずつ:nameに取り出し、SQLCODEが0でなければ(行がなくなれば)ループを抜ける
- 取り出すたびに、printfで氏名を表示する
- 最後にCLOSEで閉じる
② FETCHで取り出した行の更新
カーソル処理によるデータの更新・削除の流れ
- カーソルの宣言
- カーソルを開く
- FETCH:
- データの終わりなら、6へ
- 更新/削除:
- エラーなら、ROLLBACKして6へ
- 3に戻る
- COMMIT(正常に終わった場合)して、カーソルを閉じる
- WHERE CURRENT OF:
- FETCH文で取り出した行を、更新あるいは削除する場合は、FETCH文の後に続くUPDATE文やDELETE文のWHERE句に、「WHERE CURRENT OF カーソル名」と指定する
- 「今カーソルが指している行」という意味
- WHERE CURRENT OFの例え:
- 「しおりを挟んでいるこの行を書き換えて」と指さす
③ 処理の確定と取消し
- ROLLBACK:
- 一連のデータを更新している途中でエラーが起きた場合、それまでの更新処理を取り消し、元に戻す必要がある
- 埋込みSQLでは「EXEC SQL ROLLBACK」を指定する
- COMMIT:
- トランザクションが正常終了した場合は、「EXEC SQL COMMIT」を指定し、それまでの更新処理を確定する
- COMMITとROLLBACKの例え:
- COMMITは、書き終えた書類に「確定」のハンコを押す
- ROLLBACKは、途中で間違えたので、書きかけの書類を全部破って最初の状態に戻す
混同しやすいペア
- 埋込みSQL(親言語方式) / 対話型SQL
- 埋込みSQLは、プログラムの中にSQL文を組み込んで使う
- 対話型SQLは、利用者がSQL文を直接打ち込んで使う
- 静的SQL / 動的SQL
- 静的SQLは、あらかじめ決まったSQL文を埋め込む
- 動的SQLは、実行中にSQL文を作って実行する
- 非カーソル処理 / カーソル処理
- 非カーソル処理は、SELECT…INTOで1行だけ取り出す
- カーソル処理は、結果をファイルのように見て、FETCHで複数行を1行ずつ取り出す
- ホスト変数 / 列名
- ホスト変数は、プログラム側の変数。SQL文の中では「:」を付ける
- 列名は、データベース側の表の列
- SQLプリコンパイラ / コンパイラ
- SQLプリコンパイラは、EXEC SQL文をデータベースアクセス関数の呼出し文に変換する(事前コンパイラ)
- コンパイラは、変換後のプログラムを機械語に翻訳する
- DECLARE / OPEN
- DECLAREは、SELECT文にカーソル名を付ける(宣言するだけで、まだ実行しない)
- OPENは、SELECT文を実行し、カーソルを先頭行に位置づける
- FETCH / CLOSE
- FETCHは、カーソルが指す1行をホスト変数に取り出し、カーソルを次の行に進める
- CLOSEは、カーソルを閉じる
- SQLCODE 0 / NOT FOUND
- 0は、正常終了
- NOT FOUNDは、取り出す行がなくなったこと
- COMMIT / ROLLBACK
- COMMITは、正常終了時に更新を確定する
- ROLLBACKは、エラー時に更新を取り消して元に戻す
- WHERE CURRENT OF / 通常のWHERE句
- WHERE CURRENT OFは、カーソルが今指している行を更新・削除する
- 通常のWHERE句は、条件に合う行を更新・削除する