埋込み方式

このページでは、静的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行下にずらす

カーソル処理の流れ(★)

  1. カーソルの宣言:
    • DECLARE カーソル名 CURSOR FOR SELECT文
    • 指定したSELECT文の問合せに、カーソル名を付ける
  2. カーソルを開く:
    • OPEN カーソル名
    • SELECT文が実行され、カーソルは実行結果の先頭行を指す(カーソル位置づけ)
  3. 1行の取り出し:
    • FETCH カーソル名 INTO 結果受け取りのホスト変数
    • 1行ずつ取り出し、INTO句で指定したホスト変数に入れる。1行取り出した後、カーソルは次の行を指す
    • 取り出す行がなくなったときは、SQLCODEにNOT FOUNDコードが設定される
  4. 取り出したデータを基に処理:
    • データの終わりでなければ、3に戻って繰り返す
  5. カーソルを閉じる:
    • データの終わりなら、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で取り出した行の更新

カーソル処理によるデータの更新・削除の流れ

  1. カーソルの宣言
  2. カーソルを開く
  3. FETCH:
    • データの終わりなら、6へ
  4. 更新/削除:
    • エラーなら、ROLLBACKして6へ
  5. 3に戻る
  6. 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句は、条件に合う行を更新・削除する

← 06 データベースの目次に戻る

タイトルとURLをコピーしました