埋め込みSQL ガイド - Embarcadero

埋め込み SQL ガイド
InterBase 2009
®
www.embarcadero.com
© 2008 Embarcadero Technologies, Inc. Embarcadero、Embarcadero Technologies ロゴ、およびその他の Embarcadero
Technologies 製品名またはサービス名はすべて、Embarcadero Technologies, Inc. の商標または登録商標です。その他の
商標はすべて、個々の権利の所有者に帰属します。
目次
表
v
図
vii
複数のデータベースへの接続 . . . . . . . 3-11
接続中のエラー処理 . . . . . . . . . . . 3-12
データベースキャッシュバッファの設定 . 3-13
開かれているデータベースへのアクセス . . 3-14
テーブル名の識別 . . . . . . . . . . . . . . 3-14
データベースを閉じる . . . . . . . . . . . . 3-15
DISCONNECT でデータベースを閉じる 3-15
COMMIT と ROLLBACK によりデータベー
スを閉じる . . . . . . . . . . . . . . . 3-16
第1章
埋め込み SQL ガイドの使い方
対象読者 . . . . . . . . . . . . . . . . . . . . 1-1
このガイドの内容 . . . . . . . . . . . . . . . 1-2
第2章
第4章
アプリケーションの必要条件
トランザクションの操作
すべてのアプリケーションの必要条件 . . . . . 2-1
SQL アプリケーションを移植する場合の注意
デフォルトトランザクションの起動 . . . . . . 4-2
SET TRANSACTION なしの起動 . . . . 4-2
SET TRANSACTION によるデフォルトトラ
ンザクションの起動 . . . . . . . . . . . . 4-3
名前付きトランザクションの起動 . . . . . . . 4-4
トランザクションの命名 . . . . . . . . . . 4-5
SET TRANSACTION での動作の指定 . . 4-7
データ操作文でのトランザクション名の扱い 4-19
トランザクションの終了 . . . . . . . . . . . 4-21
COMMIT の使い方 . . . . . . . . . . . 4-22
ROLLBACK の使い方 . . . . . . . . . . 4-25
複数のトランザクションの使い方 . . . . . . 4-26
デフォルトのトランザクション . . . . . 4-26
カーソルの扱い . . . . . . . . . . . . . . 4-27
複数のトランザクションを使用する場合の処理
例 . . . . . . . . . . . . . . . . . . . . 4-28
DSQL での複数のトランザクションの使い方 4-29
“?” によるトランザクションの動作の変更 4-30
. . . . . . . . . . . . . . . . . . . . . . . 2-2
DSQL アプリケーションを移植する場合の注意
. . . . . . . . . . . . . . . . . . . . . . . 2-2
ホスト変数の宣言 . . . . . . . . . . . . . . 2-2
データベースの宣言と初期化 . . . . . . . . . 2-5
SET DATABASE の使用 . . . . . . . . . . 2-5
CONNECT の使用 . . . . . . . . . . . . . 2-6
データベースが 1 つの場合 . . . . . . . . . 2-6
SQL 文 . . . . . . . . . . . . . . . . . . . . . 2-7
エラー処理と復旧 . . . . . . . . . . . . . . . 2-7
トランザクションの終了 . . . . . . . . . . . . 2-7
変更の保存 . . . . . . . . . . . . . . . . . 2-8
変更の取り消し . . . . . . . . . . . . . . . 2-8
データベースを閉じる . . . . . . . . . . . . . 2-9
DSQL の必要条件 . . . . . . . . . . . . . . . 2-9
XSQLDA の宣言 . . . . . . . . . . . . . 2-10
DSQL に関する制限事項 . . . . . . . . . . . 2-11
データベースハンドルの使い方 . . . . . . 2-11
有効なデータベースの使い方 . . . . . . . 2-12
トランザクション名の使い方 . . . . . . . 2-12
プログラムの前処理 . . . . . . . . . . . . . 2-13
第5章
データ定義文
メタデータの作成 . . .
メタデータ名 . . . .
データベースの作成
ドメインの作成 . . .
テーブルの作成 . . .
ビューの作成 . . . .
インデックスの作成
ジェネレータの作成
メタデータの削除 . . .
インデックスの削除
ビューの削除 . . . .
テーブルの削除 . . .
メタデータの変更 . . .
第3章
データベースの操作
データベースの宣言 . . . . . . . . . . . . . . 3-1
複数のデータベースの宣言 . . . . . . . . . 3-2
前処理時と実行時のデータベース . . . . . 3-4
SET DATABASE のデータベースハンドルの
スコープ . . . . . . . . . . . . . . . . . . 3-5
接続キャラクタセットの指定 . . . . . . . . . 3-6
データベースを開く . . . . . . . . . . . . . . 3-6
CONNECT 文の基本形 . . . . . . . . . . 3-7
その他の CONNECT 構文 . . . . . . . . 3-11
i
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
. 5-2
. 5-2
. 5-3
. 5-4
. 5-5
. 5-8
5-10
5-11
5-12
5-12
5-13
5-13
5-14
テーブルの修正 . . . . . . . . . . . . . . 5-14
ビューの修正 . . . . . . . . . . . . . . . 5-17
インデックスの修正 . . . . . . . . . . . . 5-18
データの挿入 . . . . . . . . . . . . . . . . .
VALUES によるデータの挿入 . . . . . .
SELECT によるデータの挿入 . . . . . .
NULL を含んだ新規行の追加 . . . . . .
ビューを使ったデータの挿入 . . . . . . .
INSERT でのトランザクション名の指定
データの更新 . . . . . . . . . . . . . . . . .
複数行の更新 . . . . . . . . . . . . . . .
UPDATE による列への NULL の設定 .
ビューを使った更新 . . . . . . . . . . .
UPDATE でのトランザクション名の指定
データの削除 . . . . . . . . . . . . . . . . .
複数行の削除 . . . . . . . . . . . . . . .
ビューを使った削除 . . . . . . . . . . .
DELETE でのトランザクション名の指定
第6章
データ処理
サポートするデータ型 . . . . . . . . . . . . . 6-2
SQL 式 . . . . . . . . . . . . . . . . . . . . . 6-4
式での文字列演算子の使い方 . . . . . . . . 6-6
式での算術演算子の使い方 . . . . . . . . . 6-6
式での論理演算子の使い方 . . . . . . . . . 6-7
式での比較演算子の使い方 . . . . . . . . . 6-7
演算子の優先順位 . . . . . . . . . . . . . 6-14
CAST() によるデータ型の変換 . . . . . . 6-17
UPPER() によるテキストデータの大文字変更
. . . . . . . . . . . . . . . . . . . . . . 6-17
第7章
SELECT によるデータの取り出し . . . . . . 6-18
SELECT での取り出し列の指定 . . . . . 6-20
トランザクション名の指定 . . . . . . . . 6-22
INTO での変数の指定 . . . . . . . . . . 6-23
FROM でのテーブルの指定 . . . . . . . 6-24
WHERE での行の絞り込み . . . . . . . . 6-26
ORDER BY による行のソート . . . . . . 6-29
GROUP BY による複数行のグループ化 . 6-30
HAVING による複数行のグループ化 . . 6-31
ROWS による結果セットの限定 . . . . . 6-32
UNION によるテーブルの付加 . . . . . 6-33
PLAN によるクエリープランの指定 . . . 6-34
1 行の取り出し . . . . . . . . . . . . . . . . 6-35
複数行の取り出し . . . . . . . . . . . . . . 6-35
カーソルの宣言 . . . . . . . . . . . . . . 6-36
カーソルのオープン . . . . . . . . . . . . 6-37
カーソルによる行の取り出し . . . . . . . 6-38
カーソルのクローズ . . . . . . . . . . . . 6-40
カーソルによる行の取り出しのプログラム例
. . . . . . . . . . . . . . . . . . . . . .
NULL 値が格納されている行の取り出し
ビューによる行の取り出し . . . . . . . .
DSQL での複数行の取り出し . . . . . . . .
DSQL カーソルの宣言 . . . . . . . . . .
DSQL カーソルのオープン . . . . . . . .
DSQL カーソルによる複数行の取り出し .
テーブルの結合 . . . . . . . . . . . . . . . .
結合で使用する列の選択 . . . . . . . . .
内部結合 . . . . . . . . . . . . . . . . . .
外部結合 . . . . . . . . . . . . . . . . . .
ネストされた結合 . . . . . . . . . . . . .
サブクエリー . . . . . . . . . . . . . . . . .
基本的なサブクエリー . . . . . . . . . .
相関的なサブクエリー . . . . . . . . . .
6-54
6-55
6-55
6-56
6-58
6-59
6-60
6-61
6-64
6-64
6-65
6-65
6-66
6-69
6-69
日付と時刻
現在の日付と時刻の情報をデータベースに問い合
わせる . . . . . . . . . . . . . . . . . . . . 7-2
現在の日付と時刻の取得 . . . . . . . . . . 7-2
日付時刻情報の取り出し . . . . . . . . . . 7-2
日付と時刻の取り出し . . . . . . . . . . . . . 7-3
入力のための日付の書式 . . . . . . . . . . . . 7-4
日付と時刻の挿入 . . . . . . . . . . . . . . . 7-5
日付と時刻の更新 . . . . . . . . . . . . . . . 7-6
CAST() による日付と時刻の変換 . . . . . . . 7-6
SQL データ型から日付時刻データ型へのキャ
スト . . . . . . . . . . . . . . . . . . . . 7-7
日付時刻データ型から他の SQL データ型への
キャスト . . . . . . . . . . . . . . . . . . 7-8
日付リテラルの使い方 . . . . . . . . . . . . . 7-9
日付および時刻データ型の加算と減算 . . . 7-10
日付と時刻の比較 . . . . . . . . . . . . . . 7-11
日付および時刻データ型を集計関数で使用する
6-40
6-42
6-43
6-43
6-44
6-45
6-45
6-45
6-46
6-47
6-49
6-51
6-51
6-52
6-53
. . . . . . . . . . . . . . . . . . . . . . . 7-11
第8章
BLOB データの操作
BLOB の概要 . . . . . . . . . . . . . . . . . 8-1
BLOB データの格納方法 . . . . . . . . . . . 8-2
BLOB サブタイプ . . . . . . . . . . . . . 8-2
BLOB のデータベース上での格納形式 . . . 8-3
BLOB のセグメント長 . . . . . . . . . . . 8-4
DECLARE CURSOR でのセグメント長の変
更 . . . . . . . . . . . . . . . . . . . . . 8-5
SQL での BLOB データへのアクセス . . . . . 8-5
BLOB データの取り出し . . . . . . . . . . 8-6
BLOB データの挿入 . . . . . . . . . . . . 8-8
BLOB データの更新 . . . . . . . . . . . . 8-9
ii
第 12 章
BLOB データの削除 . . . . . . . . . . . 8-10
API 呼び出しによる BLOB データへのアクセス
. . . . . . . . . . . . . . . . . . . . . . . . 8-11
BLOB データのフィルタリング . . . . . . . 8-11
標準 InterBase フィルタ . . . . . . . . . 8-12
外部 BLOB フィルタ . . . . . . . . . . . 8-12
外部 BLOB フィルタの作成 . . . . . . . . . 8-14
フィルタの種類 . . . . . . . . . . . . . . 8-14
エラー処理と回復
標準のエラー処理 . . . . . . . . . . . . . . 12-1
WHENEVER 文 . . . . . . . . . . . . . 12-2
SQLCODE の直接検査 . . . . . . . . . . 12-4
WHENEVER 文と直接検査の組み合わせ 12-6
エラー処理のガイドライン . . . . . . . . 12-7
InterBase 独自のエラー処理 . . . . . . . . 12-8
エラーメッセージの表示 . . . . . . . . . 12-8
SQL エラーメッセージの取り込み . . . . 12-9
InterBase エラーメッセージの取り込み .12-10
InterBase エラーコードの処理 . . . . . .12-12
読み取り専用フィルタと書き込み専用フィルタ
. . . . . . . . . . . . . . . . . . . . . . 8-14
フィルタ関数の定義 . . . . . . . . . . . . 8-14
第9章
配列の使い方
配列の作成 . . . . . . . . . . . . . .
多次元配列 . . . . . . . . . . . .
添字範囲の指定 . . . . . . . . . .
配列へのアクセス . . . . . . . . . .
配列からのデータの取り出し . . .
配列へのデータの挿入 . . . . . .
配列スライスのデータの取り出し
配列スライスのデータの更新 . . .
検索条件での配列要素の評価 . . .
変数による配列の添字の指定 . . .
配列と算術式 . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
第 13 章
. 9-1
. 9-2
. 9-2
. 9-3
. 9-4
. 9-4
. 9-5
. 9-6
. 9-8
. 9-8
. 9-8
動的 SQL
DSQL プログラミングプロセスの概要 . . . 13-1
DSQL に関する制限事項 . . . . . . . . . . 13-1
データベースへのアクセス . . . . . . . . 13-2
トランザクションの操作 . . . . . . . . . 13-3
データベースの作成 . . . . . . . . . . . 13-4
BLOB データの処理 . . . . . . . . . . . 13-4
配列データの処理 . . . . . . . . . . . . . 13-4
DSQL アプリケーションの記述 . . . . . . . 13-5
DSQL で処理可能な SQL 文 . . . . . . . 13-5
SQL 文の文字列 . . . . . . . . . . . . . 13-6
SQL 文の文字列の値パラメータ . . . . . 13-6
XSQLDA . . . . . . . . . . . . . . . . . . 13-7
XSQLDA のフィールド . . . . . . . . . 13-9
XSQLVAR のフィールド . . . . . . . . . 13-9
入力デスクリプタ . . . . . . . . . . . . .13-11
出力デスクリプタ . . . . . . . . . . . . .13-11
XSQLDA_LENGTH マクロの使い方 . .13-11
SQL データ型マクロ定数 . . . . . . . . .13-12
可変長文字列データ型の操作 . . . . . . .13-14
NUMERIC と DECIMAL のデータ型の扱い
. . . . . . . . . . . . . . . . . . . . . .13-15
データ型の強制変換 . . . . . . . . . . .13-15
数値データの配置(アラインメント) . .13-16
DSQL のプログラミング手法 . . . . . . . .13-17
手法 1:パラメータのない非クエリー SQL 文
. . . . . . . . . . . . . . . . . . . . . .13-17
手法 2:パラメータのある非クエリー SQL 文
. . . . . . . . . . . . . . . . . . . . . .13-18
手法 3:パラメータのないクエリー SQL 文
. . . . . . . . . . . . . . . . . . . . . .13-21
手法 4:パラメータのあるクエリー SQL 文
. . . . . . . . . . . . . . . . . . . . . .13-25
第 10 章
ストアドプロシージャ
ストアドプロシージャの使い方 . . . . . . . 10-2
ストアドプロシージャとトランザクション 10-2
ストアドプロシージャとセキュリティ . . 10-2
選択プロシージャの使い方 . . . . . . . . . . 10-3
選択プロシージャの呼び出し . . . . . . . 10-4
カーソル宣言での選択プロシージャの使用 10-4
実行可能プロシージャの使い方 . . . . . . . 10-4
実行可能プロシージャの実行 . . . . . . . 10-5
DSQL アプリケーションでのストアドプロシー
ジャの実行 . . . . . . . . . . . . . . . . 10-5
第 11 章
イベントの操作
InterBase のイベントメカニズム . . . . . .
イベントの発生 . . . . . . . . . . . . . . . .
イベントとの関係の登録 . . . . . . . . . . .
複数のイベントとの関係の登録 . . . . . . .
EVENT WAIT によるイベントの通知の待機
イベントに対する応答 . . . . . . . . . . . .
11-1
11-2
11-3
11-4
11-4
11-5
iii
第 14 章
コンパイルとリンク . . . . . . .
Microsoft Windows の場合 .
Solaris の場合 . . . . . . . .
Ada プログラムのコンパイル
UNIX 上でのリンク . . . . .
前処理、コンパイル、リンク
前処理
. . . . . . . . . . . . . . . . . . .
gpre の使用 . . . . . . . . . . . . . . .
gpre クライアント ダイアレクトの設定
ファイル拡張子を用いた言語の指定 . .
ソース ファイルの指定 . . . . . . . . .
.
.
.
.
.
14-1
14-1
14-4
14-5
14-5
索引
iv
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
14-7
14-7
14-8
14-8
14-8
I-1
表
1.1
3.1
4.1
4.2
埋め込み SQL ガイドの構成 . . . . . . . 1-2
CONNECT の構文のまとめ . . . . . 3-11
トランザクション管理の SQL 文 . . . . 4-1
6.12
6.13
7.1
7.2
デフォルトトランザクションのデフォルト動
作 . . . . . . . . . . . . . . . . . . . . . 4-3
4.3 SET TRANSACTION のパラメータ . . 4-8
4.4 ISOLATION LEVEL のオプション . 4-10
4.5 InterBase でのトランザクションの競合の管
理 . . . . . . . . . . . . . . . . . . . . 4-12
4.6 排他レベルと SELECT および UPDATE と
の関係 . . . . . . . . . . . . . . . . . 4-15
4.7 RESERVING 句を使用したテーブル予約の
オプション . . . . . . . . . . . . . . 4-18
5.1 埋め込みアプリケーションで使用できるデー
タ定義文 . . . . . . . . . . . . . . . . . 5-1
6.1 InterBase でサポートするデータ型 . . . 6-2
6.2 SQL 式の構成要素 . . . . . . . . . . . . 6-4
6.3 算術演算子 . . . . . . . . . . . . . . . . 6-6
6.4 サブクエリーを必要とする InterBase の比
較演算子 . . . . . . . . . . . . . . . . . 6-8
6.5 演算子の種類別優先順位 . . . . . . . . 6-15
6.6 算術演算子の優先順位 . . . . . . . . . 6-15
6.7 比較演算子の優先順位 . . . . . . . . . 6-16
6.8 論理演算子の優先順位 . . . . . . . . . 6-16
6.9 CAST() で変換できるデータ型 . . . . 6-17
6.10 SELECT 文の句 . . . . . . . . . . . . 6-19
6.11 SQL の集計関数 . . . . . . . . . . . . 6-21
7.3
7.4
8.1
8.2
8.3
8.4
8.5
12.1
13.1
13.2
13.3
WHERE 句の検索条件の要素 . . . . . 6-27
ROWS 句の形式 . . . . . . . . . . . . 6-32
日付時刻情報の取り出し . . . . . . . . 7-2
SQL データ型から日付時刻データ型への
キャスト . . . . . . . . . . . . . . . . . 7-7
日付時刻データ型から他の SQL データ型へ
のキャスト . . . . . . . . . . . . . . . . 7-8
日付 / 時刻データ型の加算と減算 . . 7-10
InterBase で定義されている BLOB サブタ
イプ . . . . . . . . . . . . . . . . . . . 8-2
BLOB に関する API 呼び出し . . . . 8-11
isc_blob_ctl のフィールドの説明 . . . 8-17
BLOB アクセス処理 . . . . . . . . . . 8-19
BLOB フィルタの戻り値 . . . . . . . 8-20
SQLCODE の値 . . . . . . . . . . . . 12-1
XSQLDA のフィールド . . . . . . . . 13-9
XSQLVAR のフィールド . . . . . . . 13-9
SQL のデータ型、マクロ式、C のデータ型
. . . . . . . . . . . . . . . . . . . . .13-12
13.4 SQL 文の文字列と推奨される処理方法
. . . . . . . . . . . . . . . . . . . . .13-17
14.1 すべてのプラットフォームで使用可能な
gpre 言語スイッチ . . . . . . . . . . 14-2
14.2 追加の gpre 言語スイッチ . . . . . . . 14-2
14.3 gpre オプション スイッチ . . . . . . 14-3
14.4 言語固有の gpre オプション スイッチ 14-4
14.5 ファイル拡張子による言語指定 . . . . 14-5
v
vi
図
8.1 データベース中の BLOB ID と BLOB セグメ
ントとの関連 . . . . . . . . . . . . . . . 8-4
8.2 小文字のテキストから大文字のテキストへの
変換 . . . . . . . . . . . . . . . . . . . 8-13
8.3 大文字のテキストから小文字のテキストへの
変換 . . . . . . . . . . . . . . . . . . . 8-13
8.4 アプリケーション、InterBase、フィルタの
関係 . . . . . . . . . . . . . . . . . . . 8-15
13.1 XSQLDA と XSQLVAR の関係 . . . . 13-8
vii
viii
第
章
埋め込み SQL ガイドの使い方
第1章
InterBase の『埋め込み SQL ガイド』では、InterBase とプログラミング言語(C または
C++)を使用する埋め込みデータベースアプリケーション(SQL と DSQL)のプログラム記
述、前処理、コンパイル、およびリンクの方法について、実際のタスクを中心に説明しま
す。この章では、このガイドの対象読者、および各章の概要について説明します。
対象読者
InterBase の『埋め込み SQL ガイド』は、データベースアプリケーションのプログラマを
対象とし、以下についての知識があることを前提としています。
• SQL 文
• リレーショナルデータベースのプログラミング
• C プログラミング
『埋め込み SQL ガイド』では、過去に InterBase を扱った経験は特に必要とされません。
InterBase の概要については『操作ガイド』を、SQL の概要については『言語リファレンス』
を参照してください。
メモ 『埋め込み SQL ガイド』では、C または C++ 言語を使用した埋め込みプログラミング(SQL
と DSQL)について主に説明します。Delphi については扱っていません。
第 1 章 埋め込み SQL ガイドの使い方
1-1
このガイドの内容
このガイドの内容
下の表では、埋め込み SQL ガイドの各章について簡単に説明します。
表 1.1
埋め込み SQL ガイドの構成
章
説明
第 1 章「埋め込み SQL ガイドの使い方」
ガイドの構造と対象者についての説明
第 2 章「アプリケーションの必要条件」
SQL および DSQL アプリケーションのプログラミングに
共通する要素についての説明
第 3 章「データベースの操作」
データベースを扱う SQL 文の使い方についての説明
第 4 章「トランザクションの操作」
SQL 文によるトランザクションの使用とコントロールの
方法についての説明
第 5 章「データ定義文」
SQL データ定義文をアプリケーションに埋め込む方法に
ついての説明
第 6 章「データ処理」
アプリケーションで標準 SQL データの選択、挿入、更新、
および削除を行う方法についての説明
第 7 章「日付と時刻」
アプリケーションで DATE、
TIME、
および TIMESTAMP デー
タの選択、挿入、更新、および削除を行う方法について
の説明
第 8 章「BLOB データの操作」
アプリケーションで BLOB データの選択、挿入、更新、お
よび削除を行う方法についての説明
第 9 章「配列の使い方」
アプリケーションで配列データの選択、挿入、更新、お
よび削除を行う方法についての説明
第 10 章「ストアドプロシージャ」
アプリケーションでストアドプロシージャを呼び出す方
法についての説明
第 11 章「イベントの操作」
トリガーとアプリケーションの対話についての説明。ア
プリケーションでイベントの登録、イベントの待機、お
よびイベントへの応答を行う方法についての説明
第 12 章「エラー処理と回復」
アプリケーションにおける SQL 文のエラーのトラップと
処理の方法
第 13 章「動的 SQL」
DSQL アプリケーションのコーディングについての説明
第 14 章「前処理、コンパイル、リンク」
ソースコードを実行可能なアプリケーションに変換する
方法についての説明
1-2 埋 め 込 み S Q L ガ イ ド
第
章
アプリケーションの必要条件
第2章
この章では、InterBase SQL と動的 SQL(DSQL)アプリケーションのプログラミングに必
要 な 条 件 に つ い て 説 明 し ます。 これらの条件の多くは、既存のアプリケーションを
InterBase に移動する開発者にも関係します。
すべてのアプリケーションの必要条件
埋め込みアプリケーションは、InterBase のプリプロセッサである gpre で処理されることに
なります。したがって、アプリケーションにはいずれも、gpre による処理が正常に行われ
るように、適切な宣言や文が置かれていなければなりません。また、SQL とホスト言語(ア
プリケーションを記述する言語)との間で通信が可能になるような宣言や文も入れておく
必要があります。このような処理をまとめると次のようになります。
• SQL とアプリケーション間のデータのやりとりで使用される変数の宣言
• プログラムでアクセス対象とするデータベースの宣言と設定
• プログラムで使用される非デフォルトトランザクション(名前付きトランザクション)の
ためのトランザクションハンドルの作成
• SQL(およびオプションで DSQL)文の記述
• エラーの対処と回復処理
• プログラム終了前に全トランザクションおよびデータベースを閉じる処理
なお、DSQL アプリケーションや、実行時における SQL 文の作成や、ユーザーによる SQL
文の作成が可能なタイプのアプリケーションでは、上記以外の処理が必要になります。
DSQL に必要な処理の詳細は、2-9 ページの「DSQL の必要条件」を参照してください。
gpre の使い方の詳細は、第 14 章「前処理、コンパイル、リンク」を参照してください。
第 2 章 アプリケーションの必要条件
2-1
すべてのアプリケーションの必要条件
SQL アプリケーションを移植する場合の注意
既存の SQL アプリケーションを InterBase へ移植するときは、次の点を理解しておくことも
必要です。つまり、SQL アプリケーションの移植では、通常、BEGIN DECLARE SECTION
文と END DECLARE SECTION 文の間で変数を宣言しておく必要があります。これに対し
て、InterBase では、このような処理は必要ありません。移植元の SQL アプリケーションに
置かれている DECLARE SECTION は、gpre によって自動的に処理されるためです。また、
セクション内で変数を全部宣言しておくと、移植の完成度が高くなります。
DSQL アプリケーションを移植する場合の注意
InterBase には、既存の DSQL アプリケーションも移植することができます。この場合、
DSQL
アプリケーションによっては、文中で他社の SQL デスクリプタエリア(SQLDA)が使用さ
れているものもあります。このような DSQL アプリケーションを InterBase に移植する場
合、その部分を InterBase で使用されている拡張 SQLDA(XSQLDA)に修正しなければな
りません。
ホスト変数の宣言
ここでいう変数とは、標準変数の 1 つで、データベースから読み出された値の保持に使用
されるものを言います。また、データベースへの書き出しのため値を変換したり、データ
ベースの検索条件を記述した値の保存にも使用されます。変数と SQL の関係、および動作
は次のとおりです。
• データの検索時、データベース項目の値が SQL により変数に移され、この時点で値の表示
や操作が可能になります。
• ユーザーがデータを入力した場合、そのデータはいったん変数に保持されます。この後、
SQL の INSERT または UPDATE 文により InterBase へ渡されます。
• SELECT 文での検索条件の指定では、条件を直接入力したり、変数の形で入力することが
できます。たとえば、次の 2 行は SELECT 文中の WHERE 句ですが、いずれも有効です。上
の WHERE 句は直接入力の例で、下の WHERE 句は変数 country を使った例です。この場
合、COUNTRY 列で比較が行われることになります。
… WHERE COUNTRY = 'Mexico';
… WHERE COUNTRY = :country;
なお、変数は、データベース中でアクセスされるデータ列全部について必ず 1 つずつ宣言
しておかなければなりません。また、変数は、他の標準変数と同じくグローバルに宣言して
おいたり、各種グローバル宣言がまとめられている DECLARE SECTION があれば、そこに
記述しておいてもかまいません。SQL プログラムにおける、ホスト変数からの読み出し、お
よびホスト変数への書き出しの詳細は、第 6 章「データ処理」を参照してください。
SQL プログラムでの変数の宣言方法は、標準言語変数とまったく同じです。つまり、宣言、
初期化、操作については、すべて標準言語規則に準拠します。たとえば、C 言語では、変数
を事前に宣言しておくことで、SQL 文で変数として使用できるようになります。
int empno; char fname[26], lname[26];
2-2 埋 め 込 み S Q L ガ イ ド
すべてのアプリケーションの必要条件
な お、他 の SQL プ ロ グ ラ ムとの互換性を考え、BEGIN DECLARE SECTION 文と END
DECLARE SECTION 文の間で変数を宣言しておくこともできます。
セクションの宣言
SQL プログラムでは、BEGIN DECLARE SECTION 文と END DECLARE SECTION 文の間で
変数を宣言しておくのが一般的です。InterBase でも、移植性と互換性を考慮し、DECLARE
SECTION がサポートされています。この場合、構文は次のようになります。
EXEC SQL
BEGIN DECLARE SECTION;
<hostvar>;
. . .
EXEC SQL
END DECLARE SECTION;
次の例は、C 言語によるコードを使用して、1 つの DECLARE SECTION 中で empno、fname、
lname という 3 つの変数を宣言しています。
EXEC SQL
BEGIN DECLARE SECTION;
int empno;
char fname[26];
char lname[26];
EXEC SQL
END DECLARE SECTION;
このほか、変数のうち SQL 文で使用しないものは、DECLARE SECTION 文の外で宣言して
もかまいません。
BASED ON による変数の宣言
InterBase では、宣言句である BASED ON をサポートしています。この BASED ON を使用
して、データベース中の列定義をもとに C 言語の文字変数を作成することができます。
BASED ON の場合、作成した変数の容量が大きく、CHAR 列または VARCHAR 列に最大数
の文字を保持できるという特徴があります。また、ヌル終端文字のためのバイトも確保さ
れるので、C 言語の文字列関数を使用する際もほとんど問題はありません。
BASED ON は、次のように入力します。
BASED ON <dbcolumn> hostvar;
次の例は、従業員データベースの FIRSTNAME と LASTNAME という 2 つの列定義をもと
にして、fname、lname という 2 つの変数を宣言しています。
BASED ON EMP.FIRSTNAME fname;
BASED ON EMP.LASTNAME lname;
上記の文を C または C++ 言語のプログラムに埋め込んでおいた場合、前処理の際に次の変
数宣言が生成されます。
char fname[26];
char lname[26];
BASED ON は、次の手順で使用します。
第 2 章 アプリケーションの必要条件
2-3
すべてのアプリケーションの必要条件
1
SET DATABASE を使用して、取り出す列定義が含まれているデータベースを指定しま
す。
2
3
4
CONNECT を使用して、データベースにアクセスします。
BEGIN DECLARE SECTION でセクションを宣言します。
BASED ON 文を使用して、適切な型の文字列変数を宣言します。
以下は、上記の BASED ON 宣言をコンテキストに収めた例です。
EXEC SQL
SET DATABASE EMP = 'employee.ib';
EXEC SQL
CONNECT EMP;
EXEC SQL
BEGIN DECLARE SECTION;
int empno;
BASED ON EMP.FIRSTNAME fname;
BASED ON EMP.LASTNAME lname;
EXEC SQL
END DECLARE SECTION;
ホスト言語のデータ構造体
ホスト言語でデータ構造体がサポートされている場合、構造体の各データフィールドは
データベースの各列に対応することになります。次の例は、BILLING_ADDRESS という構造
体を作成する C 言語の宣言です。この宣言では、変数(データメンバー)は全部で 6 個あ
り、各変数はテーブル中の同じ名前の列に対応します。
Example 2.1ホスト言語のデータ構造体を使ってテーブル列にアクセスする
struct
{
char fname[25];
char lname[25];
char street[30];
char city[20];
char state[3];
char zip[11];
} billing_address;
SQL では、構造体の中のデータメンバーの認識は可能ですが、構造体からデータを読み
取ったり、データを構造体へ書き込んだりするには、SQL 文で個々のメンバーを指定して
おく必要があります。次の例は、テーブルのデータを読み取って、C 言語の構造体
BILLING_ADDRESS の変数に入れるための SQL 文です。
Example 2.2SQL を使ってテーブルデータを C の構造体に読み込む
EXEC SQL
SELECT FNAME, LNAME, STREET, CITY, STATE, ZIP
INTO :billing_address.fname, :billing_address.lname,
:billing_address.street, :billing_address.city,
2-4 埋 め 込 み S Q L ガ イ ド
データベースの宣言と初期化
:billing_address.state, :billing_address.zip
FROM ADDRESSES WHERE CITY = 'Brighton';
データベースの宣言と初期化
1 つの SQL プログラムからでも、複数の InterBase のデータベースに同時にアクセスできま
す。この場合、その SQL プログラム上で、アクセス対象のデータベースがすべて宣言され
ていなければなりません。また、初期化も必要で、この宣言と初期化によって SQL トラン
ザクションでデータベースへのアクセスが可能になります。一方、1 つのデータベースにし
かアクセスしないプログラムでは、gpre コマンドラインでデータベースを指定しておけば、
データベースの宣言は必要ありません。また、データベースハンドルを割り当てる必要も
ありません。
重要
DSQL プログラムの場合は、複数のデータベースへのアクセスはできません。
データベース操作用の SQL 文としては、InterBase では次の 2 つをサポートしています。
• SET DATABASE 文:アクセス対象のデータベース名の宣言、データベースハンドルの割り
当てが可能です。
• CONNECT 文:ハンドルによって指定されたデータベースを開くことができます。また、
システムリソースの割り当ても実行されます。
CONNECT 文では、データベースの指定に名前ではなくデータベースハンドルを使用しま
す。このデータベースハンドルは、トランザクション内部のテーブル名の識別にも利用でき
ます。SQL プログラムのデータベースハンドルの詳細は、第 3 章「データベースの操作」を
参照してください。
SET DATABASE の使用
SET DATABASE 文では、次の処理が可能です。
• データベースハンドルの宣言。SQL プログラムで使用するデータベースごとに宣言を行い
ます。
• データベースハンドルに対する実際のデータベース名の関係付け。 データベースハンドル
名には、通常、実際のデータベース名の略語で、覚えやすいものを選択します。
SET DATABASE では、まず、データベースハンドルを指定します。このデータベースハン
ドルが変数を示すことになります。したがって、変数を明示的に宣言する必要はありませ
ん。この SET DATABASE によりデータベースハンドルにポインタが収められ、後続の SQL
文では、このハンドルによってデータベースが参照されることになります。SET DATABASE
文は、次のように入力します。
EXEC SQL
SET DATABASE handle = 'dbname';
アクセス対象となるデータベースが複数ある場合、各データベースについて SET DATABASE
文を記述します。たとえば、employee.ib と employee2.ib という 2 つのデータベースがあり、ハン
ドルをそれぞれ DB1、DB2 と指定するときには次のように入力します。
第 2 章 アプリケーションの必要条件
2-5
データベースの宣言と初期化
EXEC SQL
SET DATABASE DB1 = 'employee.ib';
EXEC SQL
SET DATABASE DB2 = 'employee2.ib';
データベースハンドルの指定とデータベースの関係付けが終われば、以後、CONNECT な
ど後続の SQL のデータベースおよびトランザクション関連の文で、必要に応じて、このデー
タベースハンドルを使用することができます。
メモ
SET DATABASE では、オプションでユーザー名とパスワードも指定できます。
SET DATABASE のオプションの詳細は、第 3 章「データベースの操作」を参照してください。
CONNECT の使用
CONNECT 文は、データベースに接続する場合に使用します。CONNECT により、データ
ベースが開かれ、システムリソースが割り当てられます。データベースのテーブルは、デー
タベースが開かれてから使用可能になります。CONNECT は、次のようにプログラム中に入
力します。
EXEC SQL
CONNECT handle;
CONNECT 文は、アクセス対象となるデータベースが複数ある場合、各データベースにつ
いて個別に記述することも、1 つの CONNECT で複数のデータベースを指定することもで
きます。たとえば、データベースが 2 つで個別に指定する場合は次のように入力します。
EXEC SQL
CONNECT DB1;
EXEC SQL
CONNECT DB2;
また、1 つの CONNECT で一括して指定する場合は次のようになります。
EXEC SQL
CONNECT DB1, DB2;
CONNECT によりデータベースへの接続が完了すると、そのデータベースのテーブルは後
続のトランザクションで使用可能になります。データベースハンドルは、テーブル名の識別
にも使用できます。ただし、この識別は SQL アプリケーション上で有効で、DSQL アプリ
ケーションではできません。CONNECT のオプションとデータベースハンドルの扱いの詳
細は、第 3 章「データベースの操作」を参照してください。
データベースが 1 つの場合
プログラムでアクセスするデータベースが 1 つで、そのプログラムを gpre -m スイッチを使
用せずに前処理を行う場合、SET DATABASE と CONNECT は必ずしも記述する必要はあり
ません。これは、-m スイッチを使用しないときは、トランザクションが自動的に生成され
るためです。ただしこの場合でも、SET DATABASE と CONNECT はできるだけ記述するの
が理想的です。この 2 つの文を記述することで、コードの内容がわかりやすくなります。
SET DATABASE と CONNECT を省略するときは、次のような処理を行います。
2-6 埋 め 込 み S Q L ガ イ ド
SQL 文
1
プログラムコード中、グローバル変数が定義されている箇所に、DECLARE SECTION
を挿入します。この場合、プログラムで変数が使用されていなければ、空の DECLARE
SECTION でもかまいません。空の DECLARE SECTION は次のようになります。
EXEC SQL
BEGIN DECLARE SECTION;
EXEC SQL
END DECLARE SECTION;
2
プリコンパイル(前処理)時、gpre コマンドライン上でデータベース名を指定します。
ただし、プログラムに CREATE DATABASE 文が記述されているときは、データベース
の指定の必要はありません。
データベースが 1 つの場合の扱いの詳細は、第 3 章「データベースの操作」を参照してく
ださい。
SQL 文
SQL アプリケーションとは、C や C++ などのホスト言語で書かれたプログラムで、その中
に SQL 文や DSQL 文が埋め込まれているものを指します。InterBase では、各種の SQL 文、
DSQL 文をサポートしており、このような文はどのようなものでもホスト言語に埋め込むこ
とができます。埋め込みにあたっては、次の規則にしたがわなければなりません。
• 先頭にキーワードである EXEC SQL を入力します。
• ホスト言語がサポートしている文ターミネータ(文終端記号)を使って文を終了します。た
とえば、C と C++ では、ターミネータはセミコロン(;)です。
InterBase でサポートされている SQL 文と DSQL 文の詳細は、
『言語リファレンス』を参照
してください。
エラー処理と復旧
SQL 文が実行されるたびに、エラーコードが SQLCODE 変数で返されます。SQLCODE は
gpre で前処理を行う際に自動的に宣言されるので、SQL プログラム上での宣言は必要あり
ません。SQL の処理が終わった後、この SQLCODE をチェックすることで、実行時エラー
を調べたり、復旧することができます。
SQL には WHENEVER 文が用意されており、この文を使って SQLCODE の内容をチェック
したり、プログラムの流れを回復処理へ持っていくことができます。このほか、SQL 文の実
行のたびに、SQLCODE を直接実行することもできます。SQL のエラー処理と復旧の詳細
は、第 12 章「エラー処理と回復」を参照してください。
トランザクションの終了
トランザクションは、そのトランザクションでの処理が完了するたびに終了する必要があ
ります。同様に、途中でエラーが発生して処理が完了できなかったときも、終了しなけれ
ばなりません。トランザクションを終了せずにプログラムを終了した場合、limbo トランザ
第 2 章 アプリケーションの必要条件
2-7
トランザクションの終了
クションが発生することがあります。limbo トランザクションでは、レコードはデータベー
スに入力されますが、そのレコードは保存されず、入力のロールバックもできません。な
お、limbo トランザクションは、InterBase に付属しているデータベース管理ツールで削除す
ることができます。
変更の保存
トランザクションは、COMMIT 文を使って終了します。トランザクションが終了すると同
時に、トランザクションで行った変更が保存され、その変更が他のユーザーにも有効にな
ります。また、カーソルも閉じられます。COMMIT は、1 つのトランザクションの処理をす
べて無事に終了した時点で変更を保存するように実行します。COMMIT を使ってトランザ
クションを終了する場合、構文は次のようになります。
EXEC SQL
COMMIT TRANSACTION name;
たとえば、MYTRANS という名前のトランザクションをロールバックする場合、次のよう
に入力します。
EXEC SQL
COMMIT TRANSACTION MYTRANS;
SQL トランザクション制御の詳細は、第 4 章「トランザクションの操作」を参照してくだ
さい。
変更の取り消し
トランザクションで行った変更は、ROLLBACK 文を使って取り消すことができます。
ROLLBACK 文では、現在のトランザクションが終了すると同時に、カーソルも閉じられま
す。したがって、ROLLBACK は、エラーが発生してトランザクションの処理が中断したと
きに使用します。ROLLBACK 文を使ってトランザクションを終了するには次のように入力
します。
EXEC SQL
ROLLBACK TRANSACTION name;
たとえば、MYTRANS という名前のトランザクションをコミットする場合、次のように入
力します。
EXEC SQL
ROLLBACK TRANSACTION MYTRANS;
なお、トランザクションに名前がない場合(つまり、デフォルトトランザクションの場合)、
ROLLBACK は次の文を使用します。
EXEC SQL
ROLLBACK;
SQL トランザクション制御の詳細は、第 4 章「トランザクションの操作」を参照してくだ
さい。
2-8 埋 め 込 み S Q L ガ イ ド
データベースを閉じる
データベースを閉じる
現在使用しているデータベースが必要なくなった場合は、そのデータベースを閉じてから
プログラムを終了する必要があります。データベースを閉じずにプログラムを終了してし
まうと、その後、そのデータベースを使用しようとした場合に、利用できなくなったり、
データベースが破損する可能性があります。データベースは、次の 2 とおりの方法で閉じる
ことができます。
• DISCONNECT 文を使用します。この文で、データベースへの接続が解除されるとともに、
ファイルも閉じられます。
• COMMIT または ROLLBACK で RELEASE オプションを使用します。
DISCONNECT、COMMIT RELEASE、および ROLLBACK RELEASE では、次の処理が行わ
れます。
• 開かれているデータベースファイルが閉じられます。
• リモートデータベースとの接続が解除されます。
• 使用中のデータベースに関する情報や InterBase エンジンによりコンパイルされたリクエス
トがメモリ領域から解放されます。
メモ
SQL-92 標準との互換性を考慮した場合、データベースを閉じるには DISCONNECT を使用
するのが原則です。
データベースを閉じる方法の詳細は、第 3 章「データベースの操作」を参照してください。
DSQL の必要条件
これまで、SQL アプリケーションを作成する場合に必要になる処理や手続きについて説明
しましたが、このような作業は DSQL アプリケーションを作成する場合にもすべて当ては
まります。DSQL では、さらにいくつか処理が必要になります。これは、DSQL アプリケー
ションでは、実行時にユーザーがその場で SQL 文を入力することができるためです。この
種の SQL 文は数も多く、ユーザーが入力するさまざまな SQL 文に対応するため、DSQL ア
プリケーションでは次のようなプログラミング作業が必要です。
• アプリケーション上で、拡張 SQL デスクリプタエリア(XSQLDA)をできるだけ多く宣言
しておきます。XSQLDA 構造体は、通常、少なくとも 2 つは宣言します。アプリケーション
が複雑であれば、それ以上必要です。
• コンパイル時、プログラムで使用しているトランザクション名とデータベースハンドルを
残らず宣言します。トランザクション名とデータベースハンドルは、動的に扱われること
がないため、できるだけ多く宣言して実行時のユーザーの要求に応える必要があります。
• なんらかの処理を用意し、ユーザーからの SQL 文を受け取ります。
• 実際の処理に先立って、ユーザーから受け取った SQL 文を準備します。
PREPARE を使用して、文の情報を XSQLDA にロードできます。
• EXECUTE で準備された文を実際に処理します。
第 2 章 アプリケーションの必要条件
2-9
DSQL の必要条件
なお、EXECUTE IMMEDIATE 文を使用すると、1 つで PREPARE と EXECUTE の両方の機能
を同時に実行できます。EXECUTE IMMEDIATE 文については、
『言語リファレンス』を参照
してください。
また、BLOB データの場合、他のデータ型とはカーソルの構文が異なります。BLOB カーソ
ル文の詳細は、『言語リファレンス』を参照してください。
XSQLDA の宣言
拡張 SQL デスクリプタエリア(XSQLDA)は、いわば仲介領域で、この XSQLDA を介して
アプリケーションと InterBase のエンジンの間で情報が受け渡されることになります。
XSQLDA を使用することにより、次の 2 種類の処理が可能です。
• 入力パラメータをホスト言語のプログラムから SQL へ渡します。
• SELECT 文またはストアドプロシージャにより生成された出力を SQL からホスト言語のプ
ログラムに渡します。
ただし、1 つの XSQLDA では、上記の処理のうち一度にどちらか一方しか実行できません。
このため、アプリケーションでは、入力用と出力用の XSQLDA を 1 つずつ宣言するのが一
般的です。
XSQLDA 構造体は InterBase のヘッダーファイル(ibase.h)で定義されています。このヘッ
ダーファイルは、プログラムを gpre で前処理を行う際に自動的にインクルードされます。
重要
バージョン 3.3 より前の InterBase で記述された DSQL アプリケーションは、古い SQL デス
クリプタエリアである SQLDA を使用しています。現在は、SQLDA および gpre -sqlda ス
イッチはサポートされていません。このような古いアプリケーションは、XSQLDA を使用
するように変更する必要があります。
XSQLDA 構造体を作成するには、DECLARE SECTION で XSQLDA を正規のホスト言語デー
タ型として設定しておく必要があります。たとえば、次の例は、inxsqlda と outxsqlda という
2 つの XSQLDA 構造体の設定です。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
XSQLDA inxsqlda;
XSQLDA outxsqlda;
. . .
EXEC SQL
END DECLARE SECTION;
. . .
このようにして XSQLDA の宣言を記述したアプリケーションを gpre で前処理した場合、自
動的にヘッダーファイル(ibase.h)がインクルードされ、XSQLDA がホスト言語のデータ型
として定義されます。XSQLDA の構造の詳細は、第 13 章「動的 SQL」を参照してくださ
い。
2-10 埋 め 込 み S Q L ガ イ ド
DSQL に関する制限事項
DSQL に関する制限事項
プログラマは、DSQL を使用することにより、ユーザーの要求に幅広く対応できる柔軟なア
プリケーションの作成が可能になります。ただし、SQL 文のすべてを動的に扱うことができ
るとは限りません。たとえば、データベースハンドルとトランザクション名は、アプリケー
ションをコーディングする際に指定しておかなければならず、実行時にユーザーが変更し
たり指定することは不可能です。また、DSQL では、アプリケーションで複数のデータベー
スを扱えますし、複数のトランザクションの同時処理も可能ですが、次のような制限があ
ります。
• 同時に複数のデータベースにアクセスすることはできません。
• 複数のトランザクションの同時処理は、現在有効なデータベースだけで可能です。
• ユーザーが DSQL 文を使ってトランザクション名を指定することはできません。つまり、ト
ランザクション名は、アプリケーションのコーディングの段階で設定および操作する必要
があります。
データベースハンドルの使い方
データベースハンドルは必ず静的に扱われ、変更されることはありません。また、アプリ
ケーションをコーディングするときに宣言しておかなければなりません。したがって、事前
にユーザーの要求に見合った数のデータベースハンドルを宣言しておく必要があります。
これで、実行時に、ユーザーからデータベースの指定があった場合、SET DATABASE によ
り宣言したデータベースハンドルが割り当てられることになります。この処理は、たとえ
ば、C 言語のコードでは次のようになります。
. . .
EXEC SQL
SET DATABASE DB1 = 'dummydb.ib';
EXEC SQL
SET DATABASE DB2 = 'dummydb.ib';
. . .
printf("Specify first database to open: ");
gets(fname1);
printf("¥nSpecify second database to open: ");
gets(fname2);
EXEC SQL
SET DATABASE DB1 = :fname1;
EXEC SQL
SET DATABASE DB2 = :fname2;
. . .
SET DATABASE の詳細は、第 3 章「データベースの操作」を参照してください。
第 2 章 アプリケーションの必要条件
2-11
DSQL に関する制限事項
有効なデータベースの使い方
DSQL アプリケーションでは、一度に 1 つのデータベースしか使用することができません。
これは、アプリケーションで複数のデータベースに接続するように記述されている場合も
同じです。また、DSQL 文はすべて、現在の有効なデータベースに対してだけ働きます。有
効なデータベースとは、SET DATABASE 文のデータベースハンドルにより関連付けられた
最も新しいデータベースを指します。
一方、DSQL アプリケーション内の埋め込み SQL 文は、開かれているデータベース全部に
対して有効です。このため、ユーザーが入力した DSQL 文を介して、そのユーザーが指定し
たデータベースに対して処理を実行させながら、その一方で非 DSQL 文(SQL 文)を使っ
てユーザーの入力をログデータベースに記録することもできます。
SET DATABASE の詳細は、第 3 章「データベースの操作」を参照してください。
トランザクション名の使い方
SQL 文の中には、オプションでトランザクション名をパラメータとして付加できるものも
あります。この機能を使用して、たとえば、制御トランザクション(その処理部で使用さ
れるメインのトランザクション)を特定の文に対して指定することができます。トランザク
ション名は、DSQL アプリケーションでも使用できます。ただし、DSQL では、アプリケー
ションのコンパイル時にトランザクション名を宣言しておく必要があります。これで、その
トランザクション名がユーザー文に直接挿入されるようになります。ただし、そのための
処理は事前にプログラムに書き込んでおかなければなりません。
次は、宣言後、EXECUTE IMMEDIATE(EXECUTE も可)文にトランザクション名を使用し
て、制御トランザクションを指定する場合の C 言語によるコード例です。
. . .
EXEC SQL
BEGIN DECLARE SECTION:
long first, second; /* トランザクション名を宣言する */
EXEC SQL
END DECLARE SECTION;
. . .
first = second = 0L; /* 名前を 0 に初期化します */
. . .
EXEC SQL
SET TRANSACTION first; /* トランザクション 1 を開始する */
EXEC SQL
SET TRANSACTION second; /* トランザクション 2 を開始します */
printf("¥nSQL> ");
gets(userstatement);
EXEC SQL
EXECUTE IMMEDIATE TRANSACTION first userstatement;
. . .
トランザクションと名前の詳細は、第 4 章「トランザクションの操作」を参照してください。
2-12 埋 め 込 み S Q L ガ イ ド
プログラムの前処理
プログラムの前処理
SQL プログラムまたは DSQL プログラムのコーディングができたら、InterBase のプリプロ
セッサである gpre を使って前処理を実行しなければなりません。その後、プログラムはコ
ンパイルされ、リンクされます。gpre で前処理を実行すると、SQL 文と SQL 変数が、ホス
ト言語のコンパイラで認識可能な文および変数に変換されます。gpre による前処理の詳細
は、第 14 章「前処理、コンパイル、リンク」を参照してください。
第 2 章 アプリケーションの必要条件
2-13
2-14 埋 め 込 み S Q L ガ イ ド
第
章
データベースの操作
第3章
ここでは、埋め込みアプリケーションでデータベース制御用の SQL 文をどのように使用す
るかについて説明します。次のような 3 つのデータベース操作関連の SQL 文を使用して、
データベースを設定し、開き、アクセスを可能にします。
• SET DATABASE では、データベースハンドルの宣言、およびデータベースハンドルと実際
のデータベースファイルの関連付けが可能です。また、データベースにパラメータを設定
し、各種の操作を行うこともできます。
• SET NAMES では、クライアントアプリケーションで使用しているキャラクタセットの指
定が可能です。サポートされているデータ型は、CHAR、VARCHAR、テキスト BLOB の 3
種類です。クライアントアプリケーションで SET NAMES を使ってキャラクタセットを指
定しておくと、SELECT による処理の際、サーバー側でデータベースのデフォルトキャラ
クタセットが指定されたキャラクタセットにコード変換されます。反対に、INSERT や
UPDATE での処理では、クライアントアプリケーションのキャラクタセットがデータベー
スのデフォルトキャラクタセットにコード変換されます。
• CONNECT を使用して、データベースを開いて、システムリソースを割り当てることがで
きます。また、データベースにパラメータを設定し、各種の操作を行うこともできます。
データベースはいずれも、プログラムを終了する前に必ず閉じておかなければなりません。
DISCONNECT を 使 用 し て、または、プログラムの最後の COMMIT や ROLLBACK に
RELEASE オプションを追加して閉じることもできます。
データベースの宣言
データベースは、まず SET DATABASE で宣言しなければなりません。この宣言により、デー
タベースが開かれるとともにプログラムで使用可能になります。SET DATABASE では、次
の作業を行います。
• データベースハンドルを指定します。
第 3 章 データベースの操作
3-1
データベースの宣言
• 指定したデータベースハンドルに、ローカルまたはリモートのノードに存在するデータ
ベースファイルを割り当てます。
データベースハンドルは、実際のデータベース名のエイリアスを略した、一意なものを使
用 し ま す。SET DATABASE で指定したデータベースハンドルは、以後の CONNECT、
COMMIT RELEASE、ROLLBACK RELEASE 文で使用され、各文は、データベースハンドル
で示されるデータベースに対して働くことになります。データベースハンドルは、トランザ
クションブロック(処理部)の中でテーブル名の識別にも使用されます。たとえば、2 つ以
上のデータベースが開いており、各データベースの中に同じ名前のテーブルがあった場合、
データベースハンドルによりテーブルの識別、つまり特定が行われます。なお、DSQL アプ
リケーションでは、データベースハンドルによる識別は行われません。
データベースハンドルは一意でなければならず、プログラムで使用されている変数と重複
してはなりません。また、データベースハンドルの名前としては、ホスト言語の予約語は使
用できず、InterBase の予約語も使用できません。
SET DATABASE 文によるデータベースの宣言は、基本的には次のようになります。
EXEC SQL
SET DATABASE DB1 = 'employee.ib';
上の文では、employee.ib というデータベースファイルをプログラムで使用するデータベース
として指定し、このデータベースに DB1 というデータベースハンドル、つまりエイリアス
を割り当てています。
なお、プログラムが動作するディレクトリとは異なるディレクトリにデータベースファイ
ルが置かれている場合は、SET DATABASE では、フルパス名を使ってファイルを指定しな
け れ ば な り ま せ ん。 た と えば、次の SET DATABASE 宣言では、フルパス名を使って
employee.ib を宣言しています。
EXEC SQL
SET DATABASE DB1 = '/InterBase/examples/employee.ib';
また、プログラムとデータベースファイルが異なるホストに置かれているときは、データ
ベースファイル名にはホスト名も加える必要があります。次の文は、TCP/IP ネットワーク
で、UNIX のホスト名を追加してデータベースファイルを指定している例です。
EXEC SQL
SET DATABASE DB1 = 'jupiter:/usr/InterBase/examples/employee.ib';
NetBEUI プロトコルを使用した Windows ネットワークでは、パスが次のようになります。
EXEC SQL
SET DATABASE DB1 = '//venus/C:/InterBase/examples/employee.ib';
複数のデータベースの宣言
SQL プログラムでは、DSQL プログラムとは違って、複数のデータベースに同時に接続す
ることができます。このようなプログラムをマルチデータベースプログラムと言い、複数の
データベースハンドルも必要とされます。この場合、データベースハンドルには次の機能が
あります。
• マルチデータベーストランザクションでの個々のデータベースの参照
• テーブル名の識別
3-2 埋 め 込 み S Q L ガ イ ド
データベースの宣言
• CONNECT 文で開くように指示されたデータベースの特定
• DISCONNECT、COMMIT RELEASE、ROLLBACK RELEASE で閉じるように指示された
データベースの特定
一方、DSQL プログラムでは、一度に 1 つのデータベースにしかアクセスできません。この
ため、データベースハンドルの機能は、単一のデータベースとの接続と接続解除に限定さ
れます。
マルチデータベースプログラムでは、データベースはそれぞれ個別に SET DATABASE 文を
使って宣言しておかなければなりません。たとえば、2 つの SET DATABASE 文を使って 2
つのデータベースを宣言する場合、次のようになります。
. . .
EXEC SQL
SET DATABASE DB2 = 'employee2.ib';
EXEC SQL
SET DATABASE DB1 = 'employee.ib';
. . .
データベースハンドルの使用によるテーブル名の識別
アクセス対象のデータベースが複数ある場合、テーブル名が重複して使用されていること
もあります。こうしたデータベースに同時にアクセスするときは、データベースハンドル
を使ってテーブル名を識別することが必要です。この場合、handle.table のように、データ
ベースハンドルの名前を記述し、ピリオドを挟んで、テーブル名を指定します。
たとえば、次は、TEST と EMP という 2 つのデータベースハンドルを使用して、EMPLOYEE
という 2 つの同じ名前のテーブルを識別しているコード例です。
. . .
EXEC SQL
DECLARE IDMATCH CURSOR FOR
SELECT TESTNO INTO :matchid FROM TEST.EMPLOYEE
WHERE TESTNO > 100;
EXEC SQL
DECLARE EIDMATCH CURSOR FOR
SELECT EMPNO INTO :empid FROM EMP.EMPLOYEE
WHERE EMPNO = :matchid;
. . .
重要
データベースハンドルによるテーブル名の識別は、埋め込み SQL アプリケーションでのみ
可能です。DSQL アプリケーションでは、複数のデータベースへの同時アクセスはできない
ので、この機能は使用できません。
データベースハンドルを使った操作
マルチデータベースプログラムでは、SET DATABASE による宣言のほか、必ず CONNECT
文でデータベースハンドルを指定しておかなければなりません。この指定により、開く対
象となるデータベースの識別が可能になります。また、以後のトランザクションで使用す
るための準備も行われます。
第 3 章 データベースの操作
3-3
データベースの宣言
また、DISCONNECT, COMMIT RELEASE, ROLLBACK RELEASE の各文では、データベース
ハンドルを使用して、開かれているデータベースのサブセットを指定して閉じることもで
きます。
CONNECT を使ってデータベースを開いて操作するには、3-6 ページの「データベースを
開 く」 を 参 照 し て く だ さ い。 DISCONNECT、COMMIT RELEASE、または ROLLBACK
RELEASE を使ってデータベースを閉じるには、3-15 ページの「データベースを閉じる」を
参照してください。トランザクションにおけるデータベースハンドルの使い方の詳細は、
3-14 ページの「開かれているデータベースへのアクセス」を参照してください。
前処理時と実行時のデータベース
通常、SET DATABASE 文を使って 1 つのデータベースファイルを指定し、ハンドルと関連
付けます。この場合、プログラムを gpre で前処理すると、SET DATABASE で宣言したデー
タベースファイルの情報に基づいて、gpre によりプログラムのテーブルと列の参照先を検
査します。したがって、プログラムの実行時には、SET DATABASE で宣言したデータベー
スファイルと同じデータベースファイルにアクセスすることになります。必要であれば、前
処理時と実行時で異なるデータベースを指定することができます。
COMPILETIME 句の使い方
場合によっては、同じ構造を持った複数のデータベースのどれにでもアクセスできるよう
に設計されたプログラムや、実行時に使用する予定のデータベースが前処理およびコンパ
イ ル の 時 点 で は 使 用 で き ないことがあります。 このような場合、SET DATABASE に
COMPILETIME 句を追加することで、gpre が前処理時にテストするデータベースを特定す
ることができます。たとえば、次は、SET DATABASE 文に COMPILETIME 句を付加した例
です。この場合、前処理時には、実際のデータベースの有無とはかかわりなく、employee.ib
というデータベースが gpre により形式的に使用されることになります。
EXEC SQL
SET DATABASE EMP = COMPILETIME 'employee.ib';
重要
COMPILETIME キーワードに続くファイル指定は、必ず引用符で囲んだハードコードされ
た文字列にしなければなりません。
なお、SET DATABASE に RUNTIME 句ではなく COMPILETIME 句を追加し、また、後続の
CONNECT 文 で SET DATABASE と同じデータベースを指定しているときは、SET
DATABASE で指定したデータベースと同じデータベースが前処理時および実行時に使用
されることになります。前処理時と実行時で異なるデータベースを使用することを SET
DATABASE で指定する場合は、COMPILETIME 句の他に RUNTIME 句を使用します。
RUNTIME 句の使い方
前処理時にデータベースファイルを指定する場合、SET DATABASE は RUNTIME キーワー
ドおよびランタイムファイル名を使用して、COMPILETIME で指定したデータベースとは
異なるデータベースを実行時専用として指定することもできます。
EXEC SQL
SET DATABASE EMP = COMPILETIME 'employee.ib'
RUNTIME 'employee2.ib';
3-4 埋 め 込 み S Q L ガ イ ド
データベースの宣言
RUNTIME キーワードの右のファイル指定は、引用符で囲んでハードコードされた文字列で
も変数でも問題ありません。たとえば、次は、ユーザーにデータベース名の入力を要求し、
入力されたデータベース名を変数に入れる C 言語によるコード例です。この変数は、次の
SET DATABASE で使用されます。
. . .
char db_name[125];
. . .
printf("Enter the desired database name, including node
and path):¥n");
gets(db_name);
EXEC SQL
SET DATABASE EMP = COMPILETIME 'employee.ib' RUNTIME :db_name;
. . .
メモ
SET DATABASE の変数は、必ず先頭にコロンを付けなければなりません。
SET DATABASE のデータベースハンドルのスコープ
SET DATABASE で設定されたデータベースハンドルは、デフォルトでは、アプリケーショ
ンの全モジュールに対してグローバルに働きます。これを、グローバルハンドルと呼んでい
ます。このグローバルハンドルは、プログラムを構成している全部のホスト言語モジュー
ルで参照されることになります。SET DATABASE にはオプションで 2 つのキーワードがあ
りますが、これらによってスコープを調整することができます。
• STATIC を挿入した場合、データベースハンドルのスコープは SET DATABASE 文が置かれ
ているモジュールに限定されます。したがって、STATIC を宣言していないモジュールで
は、データベースハンドルは無効で使用できません。
• SET DATABASE 文に EXTERN を挿入した場合、gpre による前処理時には、その SET
DATABASE 文が置かれているモジュールの他に、通常の SET DATABASE(EXTERN なし)
を記述したモジュールがあると解釈されます。このため、いずれかのモジュールで
EXTERN キーワードを使ったときは、別のモジュールに通常の SET DATABASE 文を必ず
記述しておく必要があります。通常の SET DATABASE の記述がないときは、コンパイル
時にエラーが発生します。
上記のように、マルチモジュールプログラム(複数のモジュールで構成されるプログラム)
では、いずれかのモジュールだけに STATIC を使った SET DATABASE を記述することで、
そのモジュールにデータベースハンドルのアクセスを限定することができます。STATIC を
使用する場合の SET DATABASE の記述は次のとおりです。
EXEC SQL
SET DATABASE EMP = STATIC 'employee.ib';
また、マルチモジュールプログラムで、いずれかのモジュールに EXTERN キーワードを使っ
た SET DATABASE を記述した場合、その SET DATABASE は実際の宣言ではなく、別のモ
ジュールに実際の SET DATABASE があることを示すことになります。gpre による前処理時
には、この情報を基に処理が行われます。EXTERN キーワードを使用する場合の SET
DATABASE の記述は、次のようになります。
EXEC SQL
第 3 章 データベースの操作
3-5
接続キャラクタセットの指定
SET DATABASE EMP = EXTERN 'employee.ib';
マルチモジュールプログラムで EXTERN を使用する場合、EXTERN の参照先となっている
実際の SET DATABASE 宣言がまず行われるようにしなければなりません。また、宣言した
データベースに対して、他のモジュールよりも先に、実際の SET DATABASE を置いたモ
ジュールからアクセスするように記述します。
1 つの SET DATABASE 文には、STATIC または EXTERN キーワードのどちらか一方しか指
定できません。SET DATABASE のスコープ宣言は、COMPILETIME または RUNTIME が指
定されたデータベースにも適用されます。
接続キャラクタセットの指定
クライアントアプリケーションがデータベースに接続する場合、固有のキャラクタセット
の要件を持っている場合があります。クライアントにデータベースアクセスを提供する
サーバーには、クライアントが指定しない限り、これらの要件はわかりません。クライアン
トアプリケーションは、データベースに接続する前に SET NAMES 文で、そのキャラクタ
セットの要件を指定します。
SET NAMES 文では、データをデータベースからクライアントアプリケーションへ変換する
ときにサーバーが使用するキャラクタセットを指定します。同様に、クライアントがデータ
をデータベースに送るときは、サーバーは、そのデータをクライアントのキャラクタセッ
トからデータベースのデフォルトキャラクタセット(各列に定義したキャラクタセットが
データベースのデフォルトキャラクタセットとは異なる場合には、そのキャラクタセット)
に変換します。
たとえば、次の文は、クライアントで使用しているキャラクタセットが SJIS で、そのクラ
イアントからデータベースに接続する例です。
EXEC SQL
SET NAMES DOS437;
EXEC SQL
CONNECT 'europe.ib' USER 'JAMES' PASSWORD 'U4EEAH';
キャラクタセットの詳細は、『データ定義ガイド』を参照してください。SET NAMES と
CONNECT の構文の詳細は、
『言語リファレンス』を参照してください。
データベースを開く
データベースは、宣言の後、CONNECT 文で接続しなければなりません。これで、データ
ベースを使用できるようになります。CONNECT では、次の処理が行われます。
• データベースの使用に必要になるシステムリソースの割り当て
• データベースファイルがローカルとリモートのどちらであるかの判定。ローカルデータ
ベースとは、アプリケーションを実行しているホストに置かれているデータベースを指し
ます。リモートデータベースとは、別のホストに置かれているデータベースを指します。
• データベースを開いて、データベースが正常かどうかの確認
3-6 埋 め 込 み S Q L ガ イ ド
データベースを開く
InterBase では、ローカルであれリモートであれ、データベースへのアクセスは透過的に行
われます。また、アクセスの際、データベース構造が異常だったり、オンディスク構造体
(ODS)番号が InterBase の必要とする番号と異なっていたり、データベースが破損してい
る場合、エラーが報告されるとともにアクセスが中止されます。
CONNECT ではオプションで次の設定を行うこともできます。
• ユーザー名とパスワードの設定。
CONNECT でユーザー名とパスワードを指定しておくと、
サーバーのセキュリティデータベースとの照合が行われ、照合にパスすると接続が実行さ
れます。ユーザー名の長さは 31 文字以内となっています。パスワードは、8 文字以内に制限
されています。
• データベースへの接続時にユーザーが使用する SQL ロール名。これは、ユーザーに事前に
このロールのメンバーシップを付与されている場合に限ります。メンバーシップが付与さ
れているかどうかにかかわらず、ユーザーは ROLE 句で明示的に指定しない限り、どのロー
ルにも属しません。クライアントは一度の接続において 1 つだけロールを指定でき、再接続
しない限り別のロールに切り替えることはできません。
• アプリケーションに割り当てられるデータベースキャッシュバッファのサイズの設定。デ
フォルトのキャッシュサイズが不足したときに設定します。
CONNECT 文の基本形
CONNECT 文では、開くデータベースの名前を指定するデータベースパラメータが 1 つ以
上必要です。データベースの名前は、次のいずれかを使って指定できます。
• 事前に SET DATABASE 文を使って宣言したデータベースハンドル
• ホスト言語変数
• 引用符で囲んだハードコードされたファイル名
データベースハンドルの使い方
SET DATABASE でデータベースハンドルを宣言している場合、後続の CONNECT 文では、
引用符で囲んだハードコードされたデータベース名ではなく、できるだけデータベースハ
ンドルを使ってデータベースを指定するようにします。次に例を示します。
. . .
EXEC SQL
SET DATABASE DB1 = 'employee.ib';
EXEC SQL
SET DATABASE DB2 = 'employee2.ib';
EXEC SQL
CONNECT DB1;
EXEC SQL
CONNECT DB2;
. . .
CONNECT でデータベースハンドルの使用を推奨するのは、次のような利点があるためで
す。
• 長いファイル名でなく、簡単で覚えやすい略語でデータベースの指定が可能
第 3 章 データベースの操作
3-7
データベースを開く
• ハンドルは、マルチデータベーストランザクションでテーブル名の識別に使用することが
可能。DSQL アプリケーションでは、マルチデータベーストランザクションのサポートを
行っていません。
• 必要に応じてハンドルを他のデータベースへ割り当て直すことが可能
• CONNECT パラメータを使ってデータベースキャッシュバッファの設定が可能
データベースキャッシュバッファの個数の設定の詳細は、3-13 ページの「データベース
キャッシュバッファの設定」を参照してください。
文字列またはホスト言語変数の使用
CONNECT では、データベースハンドルのほか、実行時に用意されるデータベース名を使っ
てデータベースを指定することができます。実行時に用意されるデータベース名としては、
変数と、引用符で囲んだハードコードされたファイル名があります。
次は、アクセス対象のデータベースが 1 つのプログラムで、実行時にユーザーが指定した
ファイル名をもとに、変数を介して CONNECT を実行させる場合の C 言語のコード例で
す。
. . .
char fname[125];
. . .
printf('Enter the desired database name, including node
and path):¥n');
gets(fname);
. . .
EXEC SQL
CONNECT :fname;
. . .
ヒント
上記の処理は、同じ構造のデータベースがいくつもある場合、その中から必要なデータベー
スを選択できるようなプログラムを設計する際に特に有効です。同じ構造のデータベース
としては、CAD や CAM、その他の建築設計関連のデータベースが例として挙げられます。
複数のデータベースの処理例
上の例は、アクセス対象のデータベースが 1 つのプログラムの場合ですが、マルチデータ
ベースプログラムでも同様に、ユーザーの入力をもとに変数を使って CONNECT を実行す
ることができます。手順は、次のようになります。
1
次の SET DATABASE 構文を使ってデータベースハンドルを宣言します。
EXEC SQL
SET DATABASE handle = COMPILETIME 'dbname';
上の構文で、handle はデータベースハンドルで、プログラマが書き込みます。dbname は
引用符で囲まれてハードコードされたデータベース名で、前処理時に gpre によって使
用されます。
2
3
ユーザーに、開くデータベース名の入力を求めます。
ユーザーが入力したデータベース名を変数に保存します。
3-8 埋 め 込 み S Q L ガ イ ド
データベースを開く
4
データベースハンドルを使ってデータベースを開きます。次の CONNECT 構文で変数
とデータベースハンドルを関連付けます。
EXEC SQL
CONNECT :variable AS handle;
以上の処理は、C 言語のコードでは次のようになります。
. . .
char fname[125];
. . .
EXEC SQL
SET DATABASE DB1 = 'employee.ib';
printf("Enter the desired database name, including node
and path):¥n");
gets(fname);
EXEC SQL
CONNECT :fname AS DB1;
. . .
上記の SET DATABASE では、ハードコードされて引用符で囲まれたデータベースファイル
名がデータベースの指定に使用されています。このファイル名は、gpre による前処理で必
要になります。一方、プログラムの実行時には、変数の fname がデータベースの指定に使
用されることになります。
ハードコードされたデータベース名
1 つのデータベースにアクセスするプログラム
アクセス対象のデータベースが 1 つのプログラムでは、SET DATABASE によるデータベー
スの宣言を省略できます。この場合、CONNECT では、必ず引用符で囲んでハードコード
されたファイル名を記述しなければなりません。形式は、次のようになります。
EXEC SQL
CONNECT '[host[path]]filename';
上記の host はホスト名ですが、このホスト名はアクセスするデータベースファイルとプロ
グラムが別のノードに置かれている場合に限り必要です。また、path はパスを表しますが、
このパスもプログラムとデータベースファイルの現在の作業ディレクトリが異なる場合に
の み 必 要 で す。 た と え ば、次の例は、UNIX ホスト名とパス名を含むファイル名の
CONNECT 文です。
EXEC SQL
CONNECT 'valdez:usr/InterBase/examples/employee.ib';
メモ
データベースファイルを指定する場合のホスト構文は、サーバープラットフォームによっ
て異なります。
重要
複数のデータベースをアクセスするプログラムでは、上記のフォームの CONNECT は使用
できません。
第 3 章 データベースの操作
3-9
データベースを開く
マルチデータベースプログラム
複数のデータベースにアクセスするプログラムでは、個別の SET DATABASE 文を使用し
て、各データベースに対応するデータベースハンドルを宣言しなければなりません。ここで
宣言したデータベースハンドルは、後続の CONNECT 文で開くデータベースの特定に使用
されます。
. . .
EXEC SQL
SET DATABASE DB1 = 'employee.ib';
EXEC SQL
SET DATABASE DB2 = 'employee2.ib';
EXEC SQL
CONNECT DB1;
EXEC SQL
CONNECT DB2;
. . .
データベースを閉じた場合、そのデータベースハンドルは、以後使用されることはありま
せん。したがって、同じデータベースハンドルを別のデータベースに割り当てることができ
ます。割り当ては、データベースを閉じた後、CONNECT 文を使って行います。データベー
スはハードコードされたファイル名で指定します。次に例を示します。
. . .
EXEC SQL
DISCONNECT DB1, DB2;
EXEC SQL
CONNECT 'project.ib' AS DB1;
. . .
3-10 埋 め 込 み S Q L ガ イ ド
データベースを開く
その他の CONNECT 構文
CONNECT にはさまざまな形式がサポートされ、プログラミングに柔軟性を与えています。
次に、これらの構文を表にして紹介します。表では、構文と処理内容、例を示してありま
す。また、シングルデータベースプログラム(単一のデータベースにアクセスするプログ
ラム)とマルチデータベースプログラム(複数のデータベースにアクセスするプログラム)
で、CONNECT が使用可能かどうかについても示してあります。
表 3.1
CONNECT の構文のまとめ
構文
説明
CONNECT ‘dbfile’;
引用符で囲まれ、ハードコードされた 1 つのデータ
ベースファイル dbfile を開きます。
シングル
アクセス
複数
アクセス
可
不可
可
可
可
可
可
可
例:
EXEC SQL
CONNECT ‘employee.ib’;
handle は、すでに宣言されているデータベースハン
CONNECT handle;
ドルで、関連付けられているデータベースファイル
を開きます。CONNECT 構文では、これが推奨されて
います。
例:
EXEC SQL
CONNECT EMP;
CONNECT ‘dbfile’
handle;
AS
引用符で囲まれ、ハードコードされたデータベース
ファイル dbfile を開きます。また、handle は、すでに
宣言されているデータベースハンドルで、データ
ベースに割り当てられます。
例:
EXEC SQL
CONNECT ‘employee.ib’ AS EMP;
CONNECT
:varname AS handle;
varname は、変数で、この変数で示されるデータベー
スファイルを開きます。また、handle は、すでに宣言
されているデータベースハンドルで、このデータ
ベースハンドルがデータベースに割り当てられま
す。
例:
EXEC SQL
CONNECT :fname AS EMP;
CONNECT 構文と使い方の詳細は、
『言語リファレンス』を参照してください。
複数のデータベースへの接続
CONNECT では、複数のデータベースを一括して開くこともできます。SET DATABASE で
宣言済みのデータベースをすべて開く場合は、次の CONNECT 構文のいずれかを使用しま
す。
第 3 章 データベースの操作
3-11
データベースを開く
EXEC SQL
CONNECT ALL;
EXEC SQL
CONNECT DEFAULT;
上記の他に、宣言済みの複数のデータベースの中から、データベースを指定して開くこと
もできます。この場合、開きたいデータベースをカンマで区切って記述します。たとえば、
ハンドルを使って 2 つのデータベースを開きたいときは、次の文を使用します。
EXEC SQL
CONNECT DB1, DB2;
また、次は、2 つのデータベースをハードコードのファイル名を使って開くと同時に、各
データベースに宣言済みのデータベースハンドルを割り当てる例です。
EXEC SQL
CONNECT 'employee.ib' AS DB1, 'employee2.ib' AS DB2;
ヒント
複数のデータベースプログラムでは、そのプログラムのデータベースへのアクセス方法が
簡潔で明快な場合は、CONNECT で複数のデータベースを開く方法がたいへん効率が高く
なります。ただし、複数のデータベースの開閉を繰り返したり、データベース名を変数に置
き換えたり、また、1 つのデータベースに複数のデータベースハンドルを割り当てるような
複雑なプログラムでは、この手法の使用は控えるのが賢明です。そのようなプログラムで
は、処理に応じて CONNECT 文を個別に記述した方がコードが読みやすく、デバッグや修
正も簡単です。
接続中のエラー処理
データベースの接続中に実行時エラーが発生することもありますが、このようなエラーは
WHENEVER 文を使ってトラップし、処理します。次の例は、C 言語のコードによるエラー
処理ルーチンです。このルーチンでは、エラーメッセージが表示されるとともに、プログ
ラムが正常に終了します。
. . .
EXEC SQL
WHENEVER SQLERROR
GOTO error_exit;
. . .
:error_exit
isc_print_sqlerr(sqlcode, status_vector);
EXEC SQL
DISCONNECT ALL;
exit(1);
. . .
SOL エラーの処理の詳細は、第 12 章「エラー処理と回復」を参照してください。
3-12 埋 め 込 み S Q L ガ イ ド
データベースを開く
データベースキャッシュバッファの設定
CONNECT では、データベースを開く他に、接続したデータベースのキャッシュバッファ
の値を指定することもできます。データベースへの接続が実行されるときは、InterBase に
よってシステムメモリ上にプライベートバッファとして使用できる領域が割り当てられま
す。このバッファがデータベースキャッシュバッファで、ここにアクセス対象のデータベー
スのページが記憶され、処理速度の向上が図れます。したがって、このデータベースキャッ
シュバッファが大きくなれば、プログラムから同時にアクセスできるデータベースのペー
ジ数も多くなることになります。データベースキャッシュバッファは、そのデータベースに
対するプログラムからのアクセスの終了後に解放されます。
データベースに割り当てられるデータベースキャッシュバッファの値は、デフォルトでは
256 です。このデフォルト値は、特定のデータベースまたはサーバー全体で変更できます。
• データベースのデフォルトキャッシュバッファのサイズを再設定するには、gfix ユーティ
リティを使用します。gfix を使用したデータベースのバッファサイズの設定の詳細は、『操
作ガイド』を参照してください。
• サーバーレベルでデフォルトキャッシュバッファのサイズを変更するには、InterBase の環
境設定ファイルにある DATABASE_CACHE_PAGES の値を変更します。このオプション
は、メモリを使いすぎたり、キャッシュを小さくしすぎることがあるため、慎重に使用し
てください。
データベースごとのバッファの設定
一方、実際にアクセスするデータベースの数が多く、データベース中の行に対するアクセ
スや変更が多いプログラムでは、データベースキャッシュバッファの値を大きくすること
で処理速度を向上できる場合があります。なお、バッファの上限は、システムによって異な
ります。
• CACHE n パラメータと CONNECT を使用して、接続が持続している期間に、データベー
スに割り当てられるバッファの値を設定できます。n は、割り当てられるバッファの値で
す。データベースのバッファ値を設定するには、データベースの名前の右に CACHE n を記
述します。たとえば、次の CONNECT では、EMP というハンドルで参照されるデータベー
スに対して、500 のバッファを設定しています。
EXEC SQL
CONNECT EMP CACHE 500;
メモ
データベースで現在使用されている最小のバッファを下回るバッファサイズを指定した場
合、この要求は無視されます。
また、次の文は、TEST と EMP という 2 つのデータベースを開いています。TEST には
CACHE が指定されていないため、バッファはデフォルトの 256 のままです。一方、EMP は
CACHE 句によりバッファ値 400 で開かれます。
EXEC SQL
CONNECT TEST, EMP CACHE 400;
第 3 章 データベースの操作
3-13
開かれているデータベースへのアクセス
全データベースに対するバッファの一括設定
上記の他に、CONNECT ALL と CACHE n パラメータを使用することにより、すべてのデー
タベースに対して同じ値のバッファを一括して設定できます。たとえば、次の文は、EMP
と EMP2 という 2 つのデータベースを開くとともに、どちらのデータベースにも 400 のバッ
ファを割り当てます。
. . .
EXEC SQL
SET DATABASE EMP = 'employee.ib';
EXEC SQL
SET DATABASE EMP2 = 'test.ib';
EXEC SQL
CONNECT ALL CACHE 400;
. . .
また、次の例のように、データベースそれぞれについて CACHE を使って同じバッファ値
を設定することもできます。
. . .
EXEC SQL
CONNECT EMP CACHE 400, TEST CACHE 400;
. . .
開かれているデータベースへのアクセス
データベースが開かれる(接続される)と、データベース中のテーブルにアクセスが可能
になります。この場合、データベースとトランザクションの関係には、次の 4 とおりあり
ます。
• アクセスするデータベースが 1 つで、実行するトランザクションが 1 つ
• アクセスするデータベースが 1 つで、実行するトランザクションが複数
• アクセスするデータベースが複数で、実行するトランザクションが 1 つ
• アクセスするデータベースが複数で、実行するトランザクションが複数
トランザクションの概要については、第 4 章「トランザクションの操作」を参照してくだ
さい。
テーブル名の識別
SQL では、複数のデータベースにアクセスしながら複数のトランザクションを実行する場
合、特に注意が必要です。たとえば、複数のデータベースにそれぞれ同じ名前のテーブルが
格納されていることがあります。この場合、トランザクションの実行の際は、テーブル名
の前にデータベースハンドルを付けてテーブル名を識別しなければなりません。
テーブル名を識別する場合、次のように、ピリオドを挟んでデータベース名とテーブル名
を記述します。
3-14 埋 め 込 み S Q L ガ イ ド
データベースを閉じる
handle.table
た と え ば、次 の 例 は、TEST と EMP という 2 つのデータベースがあり、どちらにも
EMPLOYEE という同じ名前のテーブルが格納されている場合のカーソルの宣言です。ここ
では、テーブル名である EMPLOYEE の前に TEST と EMP を付けて、参照先のテーブルを
識別しています。
. . .
EXEC SQL
DECLARE IDMATCH CURSOR FOR
SELECT TESTNO INTO :matchid FROM TEST.EMPLOYEE
WHERE (SELECT EMPNO FROM EMP.EMPLOYEE WHERE EMPNO = TESTNO);
. . .
メモ
DSQL では、1 つの文で複数のデータベースにアクセスすることはできません。
データベースを閉じる
データベースの使用が終わったら、そのデータベースを閉じなければ(接続解除しなけれ
ば)なりません。SQL では、次の方法でデータベースを閉じることができます。
• DISCONNECT を使用して、データベースを接続解除してファイルを閉じます。
• COMMIT または ROLLBACK に RELEASE オプションを追加して、データベースから接続
解除してファイルを閉じます。
DISCONNECT、COMMIT RELEASE、および ROLLBACK RELEASE では、次の処理が行わ
れます。
• 開かれているデータベースファイルが閉じられます。
• リモートデータベースに接続している場合は、その接続解除を行います。
• データベースのメタデータ(データベースのシステムテーブル)情報と InterBase エンジン
によってコンパイルされたリクエストを保持しているメモリを解放します。
メモ
SQL-92 標準との互換性を考慮した場合、データベースは DISCONNECT で閉じるのが理想
的です。また、データベースは必要でなくなった時点で閉じるようにします。いったん閉じ
たデータベースは、再度開いてリソースが割り当てられた時点で、また使用できるように
なります。
DISCONNECT でデータベースを閉じる
開いた状態のデータベースをすべて接続を接続解除して閉じる場合、構文は次のようにな
ります。
EXEC SQL
DISCONNECT {ALL | DEFAULT};
つまり、次のどの文でも、開いた状態のデータベースをすべて閉じることができます。
EXEC SQL
第 3 章 データベースの操作
3-15
データベースを閉じる
DISCONNECT ALL;
EXEC SQL
DISCONNECT DEFAULT;
また、データベースハンドルをカンマで区切って指定することで、複数のデータベースを
閉じることができます。構文は次のとおりです。
EXEC SQL
DISCONNECT handle [, handle ...];
たとえば、次の文では、ハンドルが DB1 と DB2 の 2 つのデータベースを閉じます。
EXEC SQL
DISCONNECT DB1, DB2;
メモ
データベースは、そのデータベースに関連しているトランザクションがすべて終了してか
ら閉じなければなりません。なお、トランザクションの終了の前に閉じた場合、再度開い
てリソースを再割り当てする必要があります。
COMMIT と ROLLBACK によりデータベースを閉じる
開かれているデータベースを全部一括して閉じる場合、COMMIT または ROLLBACK も使
用できます。構文は次のとおりです。
EXEC SQL
{COMMIT | ROLLBACK} RELEASE;
たとえば、次は、開いた状態のデータベースを COMMIT を使って全部閉じる場合です。
EXEC SQL
COMMIT RELEASE;
このほか、COMMIT または ROLLBACK では、データベースを指定して閉じることもでき
ます。この場合、RELEASE に続けてパラメータとしてデータベースハンドルを指定します。
構文は次のとおりです。
EXEC SQL
COMMIT | ROLLBACK RELEASE handle [, handle ...];
次の例は、ROLLBACK 文で 2 つのデータベースを閉じる場合です。
EXEC SQL
ROLLBACK RELEASE DB1, DB2;
3-16 埋 め 込 み S Q L ガ イ ド
第
章
トランザクションの操作
第4章
SQL には、データ定義およびデータ操作関連の文があり、トランザクションのコンテキス
トと関連して働きます。トランザクションとは、データと SQL 文の仲介役であり、プログ
ラムでは、このトランザクションと関連 SQL 文を使ってなんらかのタスクを実行すること
になります。この章では、SQL のトランザクション操作文を使用するトランザクションの制
御、および起動と終了の方法について説明します。
表 4.1
トランザクション管理の SQL 文
文
用途
SET TRANSACTION
トランザクションの起動、名前の割り当てが可能です。また、SET
TRANSACTION では、パラメータを使ってトランザクションの動作の
指定が可能です。パラメータのタイプは、次のとおりです。
アクセスモード:書き込みや読み取りなど、トランザクションで可能
になる動作を指定できます。
ロック対応:ロックの競合が起こったときの対応方法を指定できます。
排他レベル:トランザクションに与えられるデータベースのビューの
設定に使用します。
別のトランザクションから同一のデータベースに対
してなんらかの処理が発生した場合の対応方法を決めておくことがで
きます。
テーブル予約:通常、テーブルへのアクセスは、読み取り、書き込み
時にそのつど行われますが、
トランザクションの起動時に事前にアクセ
スするテーブルをロックしておくことができます。
データベース指定:開いた状態のデータベースのいくつかを指定し、そ
のデータベースにトランザクションの処理を限定することができます。
COMMIT
トランザクションでの変更をデータベースに保存する場合に使用しま
す。保存と同時に、トランザクションが終了します。
ROLLBACK
トランザクションでの変更の取り消しが可能です。それまでの変更は
データベースにコミットされずに、トランザクションが終了します。
第 4 章 トランザクションの操作
4-1
デフォルトトランザクションの起動
上記のトランザクション操作文でトランザクションの性質を定義することができます。ま
た、同一のデータに対して、別のトランザクションからアクセスがあったときの動作や対
応を指定しておくこともできます。この場合、別のトランザクションは、他のアプリケー
ションのものであってもかまいません。
InterBase では、次の 2 種類のトランザクションを使用できます。
• 1 つはデフォルトトランザクションで、事前に GDS__TRANS という名前が付けられていま
す。プログラムで、SET TRANSACTION 文がないのになんらかのトランザクションを必要
とする文があった場合、このトランザクションが自動的に使用されます。アクセスモード
やロック対応など、GDS__TRANS の動作内容は事前に決められています。ただし、このデ
フォルト設定は、SET TRANSACTION でパラメータを付加して変更することができます。
GDS__TRANS は、isc_tr_handle 型のグローバル変数として扱います。
メモ
SET TRANSACTION を記述せず、デフォルトトランザクションを使用する場合、gpre -m ス
イッチを付けないで前処理を実行しなければなりません。
• もう 1 つは名前付きトランザクションで、SET TRANSACTION 文によって起動されます。
名前はトランザクションごとに異なり、
通常は SET TRANSACTION でパラメータを使って
トランザクションの動作を指定します。
複数トランザクションを使用する場合と命名規則を除いて、デフォルトトランザクション
も名前付きトランザクションも同じようにトランザクションを制御できます。どの場合で
も、SET TRANSACTION にパラメータを付加することでアクセス、ロック対応、および排
他レベルを指定できます。
gpre の詳細は、第 14 章「前処理、コンパイル、リンク」を参照してください。トランザ
クションの動作の詳細は、4-7 ページの「SET TRANSACTION での動作の指定」を参照
してください。
デフォルトトランザクションの起動
動作を指定せずにトランザクションを起動した場合、次のデフォルトの動作が使用されます。
READ WRITE WAIT ISOLATION LEVEL SNAPSHOT
使用するトランザクションが 1 つのプログラムでは、このデフォルトトランザクションを
利用するのが有効です。これは、SET TRANSACTION の記述がなくても、必要な場合に自
動的にデフォルトトランザクションが起動するためです。デフォルトトランザクションは、
プログラム中に SET TRANSACTION を記述して明示的に起動することもできます。
SET TRANSACTION なしの起動
トランザクションが 1 つの簡単なプログラムでは、
SET TRANSACTION を省略できます。た
とえば、次のプログラムでは、SELECT 文によりデフォルトトランザクションが自動的に起
動し、処理が行われます。
. . .
EXEC SQL
SELECT * FROM CITIES
WHERE POPULATION > 4000000
4-2 埋 め 込 み S Q L ガ イ ド
デフォルトトランザクションの起動
ORDER BY POPULATION, CITY;
. . .
このように、トランザクションが 1 つのプログラムでは SET TRANSACTION を記述する必
要はありません。ただし、トランザクションの動作を指定するときは SET TRANSACTION
を記述する必要があります。また、DSQL プログラムで、gpre -m スイッチにより前処理を
行う場合にも、SET TRANSACTION の記述が必要です。
gpre による前処理時には、SET TRANSACTION 文はなくても、SELECT などのようにトラ
ンザクションを必要とする文が見つかった場合、gpre により自動的にデフォルトトランザ
クションが生成されます。ただし、gpre に -m スイッチが付けられている場合は、デフォル
トトランザクションの生成は行われません。また、前処理時には、トランザクションの動作
としては、事前に指定されているデフォルトの動作が採用されます。実行時には、同一の
データに対して別のトランザクションからアクセスがあった場合、このデフォルトの動作
により対応が行われることになります。
重要
DSQL プログラムでトランザクションを使用する場合は、必ず SET TRANSACTION を記述
しなければなりません。この場合、gpre -m スイッチにより前処理を行います。-m スイッチ
を付加したときは、デフォルトトランザクションの自動生成は行われません。したがって、
前処理の際、SET TRANSACTION によるトランザクションの指定がないときにはエラーが
報告されます。
変更が可能なトランザクション動作の詳細は、4-7 ページの「SET TRANSACTION で
の動作の指定」を参照してください。gpre -m スイッチの使い方の詳細は、第 14 章「前処
理、コンパイル、リンク」を参照してください。
SET TRANSACTION によるデフォルトトランザクションの起動
SET TRANSACTION をパラメータなしで記述した場合、デフォルトトランザクション
(GDS__TRANS)が起動します。デフォルトの動作は次のとおりです。
READ WRITE WAIT ISOLATION LEVEL SNAPSHOT
次の表は、パラメータごとに設定と動作をまとめたものです。
表 4.2
メモ
デフォルトトランザクションのデフォルト動作
パラメータ
設定
用途
アクセスモード
READ WRITE
アクセスモード。この設定では、トランザクションで
データの選択、挿入、更新、削除が可能になります。
ロック対応
WAIT
ロック対応。この設定では、トランザクションの実行
時、テーブルと列がロックされている場合に待機状態
に入ります。その後、ロックが解放されると更新が行
われます。したがって、すぐにロックの競合エラーが
報告されることはありません。
排他レベル
ISOLATION LEVEL
SNAPSHOT
この設定では、データベースのビューはトランザク
ションの起動時のまま維持されます。したがって、別
のトランザクションによりデータベースに変更が加え
られても、データベースのビューは変わりません。
デフォルトトランザクションを明示的に起動するのは優れたプログラミング手法と言えま
す。この方が、プログラムのソースコードが理解しやすくなります。
第 4 章 トランザクションの操作
4-3
名前付きトランザクションの起動
次の文は同じ意味を持ちます。どちらの場合でも、デフォルトトランザクションがデフォル
トの動作で起動されます。
EXEC SQL
SET TRANSACTION;
EXEC SQL
SET TRANSACTION NAME gds__trans READ WRITE WAIT ISOLATION LEVEL
SNAPSHOT;
デ フ ォ ル ト ト ラ ン ザ ク シ ョ ン の デ フ ォ ル ト の 動 作 を 変 更 し て 起 動 す る 場 合、SET
TRANSACTION を使用して、デフォルトとは異なる動作を指定しなければなりません。特
に指定がない場合は、デフォルトの動作が使用されます。たとえば、次の文は、アクセス
モードとして READ ONLY を使ってトランザクションを起動する例です。この場合、READ
ONLY 以外は指定していないので、ロック対応としては WAIT が、排他レベルとしては
ISOLATION LEVEL SNAPSHOT が使用されます。
EXEC SQL
SET TRANSACTION READ ONLY;
上の例でわかるように、デフォルトトランザクションを起動するときには NAME 句を省略
することができます。
重要
DSQL では、PREPARE や EXECUTE に SET TRANSACTION を付加してデフォルトトランザ
クションの動作を変更できます。記述方法は、SET TRANSACTION の場合とほぼ同じです。
デフォルトトランザクションの動作を変更しているときは、gpre -m スイッチを使って前処
理を行う必要があります。
-m スイッチを使った前処理の詳細は、第 14 章「前処理、コンパイル、リンク」を参照し
てください。トランザクション動作と変更の詳細は、4-7 ページの「SET TRANSACTION
での動作の指定」を参照してください。
名前付きトランザクションの起動
1 つのアプリケーションで複数のトランザクションを同時に起動することができます。
InterBase では、トランザクション操作文やデータ操作文が多数用意されており、トランザ
クション名を付けることができます。複数のトランザクションが動作中の場合、トランザ
クション名によりトランザクションが識別され、トランザクションと文との関係が保たれ
ます。
同時に複数のトランザクションを使用するプログラムでは、トランザクション名を使って
他のトランザクションとの識別を行う必要があります。また、あるトランザクションが動作
中に別のトランザクションを起動する場合は、一意なトランザクション名および SET
TRANSACTION 文が個別に必要になります。名前付きトランザクションの場合も、SET
TRANSACTION でパラメータを使って動作の指定が可能です。
プログラムで名前付きトランザクションを使用する場合、処理の手順は次のようになりま
す。
1
各トランザクション名を一意な変数で宣言します。C または C++ では、トランザクショ
ン名は long 型ポインタとして宣言します。
2
各トランザクション名を 0 に初期化します。
4-4 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
3
SET TRANSACTION と有効なトランザクション名を使って各トランザクションを起動
します。
4
重要
後続のトランザクション操作文やデータ操作文にトランザクション名を記述します。こ
の場合、文とトランザクションとの関連が切れないようにします。
DSQL 文では、名前付きトランザクションの扱いが多少異なります。詳細は、4-29 ページ
の「DSQL での複数のトランザクションの使い方」を参照してください。
複数のトランザクションのプログラムの作成の詳細は、4-26 ページの「複数のトランザク
ションの使い方」を参照してください。
トランザクションの命名
トランザクション名はプログラマが変数で設定します。SQL 文では、この変数を使ってト
ランザクションを識別します。なお、トランザクション制御やデータ操作関連の SQL 文で
トランザクション名を使用しなかった場合は、その文はデフォルトトランザクション
(GDS__TRANS)に対して働くことになります。
次は、データ型 isc_tr_handle を使用して、2 つのトランザクション名の宣言および初期化を
行う C のコード例です。SET TRANSACTION 文では、続いてこれらのトランザクションの
起動も行います。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
isc_tr_handle t1, t2; /* トランザクション名を宣言する */
EXEC SQL
END DECLARE SECTION;
. . .
t1 = t2 = (isc_tr_handle) NULL; /* 名前を 0 に初期化します */
. . .
EXEC SQL
SET TRANSACTION NAME t1; /* デフォルトの動作で trans を起動します */
EXEC SQL
SET TRANSACTION NAME t2; /* デフォルトの動作で trans2 を起動します */
. . .
このコードの各手順の詳細は、以下の節で説明します。
上記のように宣言したトランザクション名は、データ操作文やトランザクション操作文の
中にオプションパラメータとして含めることができます。なお、複数のトランザクションを
扱うプログラムでトランザクション名を省略した場合、その文ではデフォルトトランザク
ション(GDS__TRANS)が使用されます。
データ操作文でトランザクション名を使用する方法の詳細は、第 6 章「データ処理」を参
照してください。
第 4 章 トランザクションの操作
4-5
名前付きトランザクションの起動
トランザクション名の宣言
トランザクションを使用するには、事前にトランザクション名を宣言しておかなければな
りません。この場合、トランザクション名は、ホスト言語のポインタとして宣言します。な
お、C または C++ では、トランザクション名は long 型ポインタで宣言しなければなりませ
ん。
次は、2 つのトランザクション名を宣言しているコード例です。
EXEC SQL
BEGIN DECLARE SECTION;
isc_tr_handle t1;
isc_tr_handle t2;
EXEC SQL
END DECLARE SECTION;
メモ
上記の例では、DECLARE SECTION でトランザクション名の宣言を行っています。InterBase
では、トランザクション名の宣言は必ずしも DECLARE SECTION 中で行う必要はありませ
ん。ただし、SQL ではトランザクション名の他にも変数としてセクションを宣言しておか
なけ れ ばな ら ない もの も あり ま す。こ れ ら を 考 慮 す る と、互 換 性 の 点 で、DECLARE
SECTION でトランザクション名を宣言しておくことをお勧めします。
DECLARE SECTION で宣言したトランザクション名は、通常、モジュールレベルでグロー
バルに宣言されます。その他、ローカルに宣言することもできますが、その場合は次の点に
注意します。
• 名前を宣言したトランザクションは、そのモジュール内だけで使用するようにします。 ま
た、エラーが発生したとき、トランザクションによる処理をロールバックするためのエラー
処理ルーチンを収めておきます。エラー処理には ROLLBACK を使用できます。ROLLBACK
によりトランザクション名が解放され、値に NULL が設定されます。
• 宣言したトランザクション名は、そのモジュールの外では使用しないようにします。
上記のように、トランザクション名は宣言したモジュール内で有効ですが、別のモジュー
ルから参照する必要があるときは、トランザクション名を外部変数として宣言しておきま
す。たとえば、t1 と t2 という 2 つのトランザクション名を外部変数として宣言する場合、C
では次のようになります。
EXEC SQL
BEGIN DECLARE SECTION;
extern isc_tr_handle t1, t2;
EXEC SQL
END DECLARE SECTION;
トランザクション名の初期化
トランザクション名の宣言が終わったら、トランザクション名を 0 に初期化します。この
初期化により、トランザクション名が実際に使用できるようになります。たとえば、次は、
2 つのトランザクション名を初期化する C のコード例です。
/* トランザクション名を 0 に初期化します */
t1 = t2 = (isc_tr_handle) NULL;
上記のようにトランザクション名の宣言と初期化が終了すると、次のような処理を行うこ
とができるようになります。
4-6 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
• 名前によるトランザクションの起動: 複数のトランザクションを同時に使用するプログラ
ムでは、トランザクション名を使ってなんらかの処理を行うことになります。なお、デフォ
ルトトランザクションでは、名前の指定は必要ありません。
• データ操作文で使用するトランザクションの指定: 複数のトランザクションを使用するプ
ログラムでは、データ操作文でトランザクション名を指定する必要があります。ただし、
デフォルトトランザクションを使用する場合は、その必要はありません。
• 複数のトランザクションを使用するプログラムでは、トランザクション名を指定して、そ
の処理をコミットまたはロールバックします。
SET TRANSACTION での動作の指定
名前付きトランザクションは、SET TRANSACTION を使って起動します。この場合、その
トランザクションの動作を指定することもできます。名前付きトランザクションをデフォ
ルトの動作のまま起動する場合は、次のような構文になります。
SET TRANSACTION NAME name;
SET TRANSACTION にパラメータを付けないでトランザクションを起動した場合、デフォ
ルトの動作が有効になります。この場合のデフォルトの動作についての概要は、4-3 の表
4.2 「デフォルトトランザクションのデフォルト動作」を参照してください。たとえば、次
の 2 つの文は内容的には同じです。いずれも、t1 という名前のトランザクションがデフォル
トの動作で起動されます。
EXEC SQL
SET TRANSACTION NAME t1;
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE WAIT ISOLATION LEVEL SNAPSHOT;
次の表は、デフォルトのトランザクションの動作を指定する SET TRANSACTION パラメー
タ(オプション)の一覧です。
第 4 章 トランザクションの操作
4-7
名前付きトランザクションの起動
表 4.3
SET TRANSACTION のパラメータ
パラメータ
設定
用途
アクセス
モード
READ ONLY または READ WRITE
このパラメータを使用して、トランザクションのテーブ
ルに対する動作を指定できます。アクセスモードについ
ては、4-9 ページの「アクセスモード」を参照してくだ
さい。
ロック対応
WAIT または NO WAIT
更新や削除の際に行がロックされていた場合、そのロッ
クに対する対応方法を選択します。WAIT を指定した場
合は、ロックが解除されるのを待って更新が行われます。
一方、NO WAIT では、即座にロックの競合エラーメッ
セージが出されます。ロック対応については、4-16 ペー
ジの「ロック対応」を参照してください。
排他レベル
SNAPSHOT を指定しておくと、トランザク
現在アクセスしているテーブルに対して別のトランザク
ションからアクセスがあった場合、そのアクセスに対し
てどのように対処するかを指定します。
ションの起動時のデータベースのビューが
そのまま維持されます。他の動作中のトラン
ザクションにより更新が行われても、ビュー
は変更されません。
SNAPSHOT TABLE STABILITY を指定し
た場合、現在、トランザクションにより読み
取りや更新が実行されているテーブルに対
して、他のトランザクションによる変更が禁
じられます。ただし、テーブルの列の読み取
りだけは、他のトランザクションから行うこ
ともできます。
READ COMMITTED を指定しておくと、
更新や削除時に、最後にコミットされた列を
使って読み取りが行われます(ロック対応と
してデフォルトの WAIT が指定されている
場合)。また、更新時、他のトランザクショ
ンと競合が起こらなければ、変更することも
できます。
READ COMMITTED 排他レベルでは、読み取る行の
バージョンを指定できます。次の 2 つのオプションが用
意されています。
• RECORD_VERSION: 必ず、最後にコミットされた
行を使って読み取りが行われます。つまり、コミッ
トされていないが、それより新しい行がディスクに
置かれている場合でも、最後にコミットされた行を
使って読み取りが実行されます。
• NO RECORD_VERSION: コミットされたかどうか
にかかわりなく、最後の行を使って読み取りが行わ
れます。また、 NO RECORD_VERSION と併せて
WAIT が指定されている場合、最後の行についてコ
ミットまたはロールバックが行われるまでいったん
待機し、その後、読み取りが行われます。NO WAIT
を指定し、コミットされた行が最新のバージョンで
ない場合、トランザクションは即座にエラー(デッ
ドロック)を返します。
テーブル
予約
RESERVING
トランザクションで利用可能なテーブルを指定してロッ
クします。このロックを行った直後、ロックしたテーブ
ルには、他のトランザクションはアクセスできなくなり
ます。
データベース
指定
USING
トランザクションがアクセスできるデータベースを限定
します。したがって、ここで限定した以外のデータベー
スには、このトランザクションではアクセスできなくな
トランザクショ
ります。この USING を使用することで、
ンで必要になるシステムリソースの量を減らすことがで
きます。
メモ:USING は、 DSQL では使用できません。
4-8 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
SET TRANSACTION の構文は次のとおりです。
EXEC SQL
SET TRANSACTION [NAME name]
[READ WRITE| READ ONLY]
[WAIT | NO WAIT]
[[ISOLATION LEVEL] {SNAPSHOT [TABLE STABILITY]
| READ COMMITTED [[NO] RECORD_VERSION]}]
[RESERVING <reserving_clause>
| USING dbhandle [, dbhandle ...]];
<reserving_clause> = table [, table ...]
[FOR [SHARED | PROTECTED] {READ | WRITE}] [, <reserving_clause>]
以下の節では、トランザクションオプションの詳細について説明します。
アクセスモード
アクセスモードでは、そのトランザクションで可能になるテーブルへのアクセス方法を指
定できます。設定できるアクセスモードは次の 2 種類です。
• READ ONLY を指定した場合、そのトランザクションでテーブルデータの選択(読み取り)
はできますが、テーブルへのデータの挿入、更新、削除はできません。
• READ WRITE を指定した場合、そのトランザクションでテーブルデータの選択、挿入、更
新、削除のいずれも可能になります。デフォルトはこの設定で、記述しないときにはこの
設定が使用されます。
InterBase では、トランザクションはデータの読み取りと書き込みの両方が可能なことを前
提としています。したがって、
SET TRANSACTION 文で READ WRITE が省略されていても、
トランザクションは、読み取りと書き込みが可能な状態で起動されるようになっています。
たとえば、次の 2 つの SET TRANSACTION では、いずれも t1 というトランザクションが
READ WRITE で起動されます。
EXEC SQL
SET TRANSACTION NAME t1;
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE;
ヒント
アクセスモードは、デフォルトの READ WRITE を使用する場合であっても、指定すること
が理想的なプログラミング方法です。これにより、アプリケーションのソースコードが読み
やすくなり、デバッグもしやすくなります。プログラムの意図は明確に記述するのが原則
です。
READ ONLY は、データの読み取りだけが必要なときに使用します。READ ONLY は、READ
WRITE と違って、必ず記述しなければなりません。たとえば、t1 というトランザクション
を読み取り専用で起動する場合は、次のように記述します。
EXEC SQL
SET TRANSACTION NAME t1 READ ONLY;
第 4 章 トランザクションの操作
4-9
名前付きトランザクションの起動
排他レベル
排他レベルでは、トランザクションによりテーブルにアクセスが行われる場合のトランザ
クションの独立性(隔離の程度)を指定できます。このパラメータでは、次の事項が制御さ
れることになります。
• トランザクションから見ることのできるデータベースのビュー
• テーブルへのアクセス方法、および別のトランザクションによるテーブルへのアクセス方
法
InterBase で指定できる排他レベルは次の 3 種類です。
表 4.4
ISOLATION LEVEL のオプション
排他レベル
用途
SNAPSHOT
デフォルトの排他レベルで、この設定では、トランザクションが起動し
たときのデータベースのビューが用意されます。このビューは、コミッ
ト済みのビューで変更されることはありません。データベースの行に対
しては、他の動作中のトランザクションからも更新と挿入が可能です
が、その変更はビューに一切影響しません。この設定で起動されたトラ
ンザクションにとっては、トランザクションの起動時に保存されていた
行が現在見える行、つまり読み取り可能な行ということになります。ま
た、この設定で起動されたトランザクションによって行の更新や削除が
試みられた場合、その行が別のトランザクションによってすでに変更が
加えられていた場合は、更新競合が報告されます。
SNAPSHOT TABLE
STABILITY
この設定では、この設定で起動されたトランザクション以外のトランザ
クションは、同一のテーブルに対して挿入や更新、削除ができなくなり
ます。ただし、テーブルの行の読み取りだけは、他のトランザクション
から行うこともできます。
READ COMMITTED
この設定では、データベース中のコミット済みデータ全部に対して読み
取りが可能になります。また、他のトランザクションによって更新、コ
ミットされた行に対しても更新が可能です。この場合、更新はコミット
済みデータに対して行われるため、更新喪失は起こりません。
トランザクションの排他レベルには、SNAPSHOT か READ COMMITTED を使用するよう
にします。どちらの設定も、同じデータベースのデータに対して複数のトランザクションで
同時に選択、挿入、更新、削除が可能です。また、ロックの競合の確率も最小限に抑える
ことができます。ロックの競合が発生する状況としては次の 2 つがあります。
• 別のトランザクションによりすでに更新や削除が行われた行に対して、さらに更新を実行
した場合。SNAPSHOT で起動されたトランザクションで発生するロックの競合が、この
ケースに該当します。これは、InterBase では、更新が行われた行がロックされるため引き
起こされます。ロックされた行は、その更新を行ったトランザクションによりコミットま
たはロールバックが完了した時点で、別のトランザクションによる更新が可能になります。
一方、排他レベルを READ COMMITTED に設定したトランザクションでは、別のトランザ
クションによって行の更新が実行された場合でも、その後、コミットされた時点で同じ行
の読み取りや更新が行われます(デフォルトの WAIT と NO RECORD_VERSION が指定され
ている場合)
。
• SNAPSHOT TABLE STABILITY によってロックされているテーブルの行に対して、別のト
ランザクションから挿入、更新、削除が試みられた場合。SNAPSHOT TABLE STABILITY を
設定したときは、テーブル全体がロックされて書き込みはできなくなります。このため、
4-10 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
他のトランザクションから更新要求があった場合、ロックの競合が発生することになりま
す。なお、SNAPSHOT や READ COMMITTED が設定されているトランザクションからの
読み取りは可能です。
SNAPSHOT TABLE STABILITY を使用することで、テーブルの変更が可能なトランザクショ
ンを 1 つに絞ることができます。ただし、テーブルはロックされるため、複数のトランザ
クションから同時にアクセスが行われるような環境では、ロックの競合の確率が増すこと
になります。ロックの競合の可能性の詳細は、4-15 ページの「排他レベルの相互作用」を
参照してください。
SNAPSHOT、READ COMMITED、
および SNAPSHOT TABLE STABILITY の安定度の相違
トランザクション操作文に関連して発生する問題としては、基本的に次の 5 つがあります。
このような問題に対しては、排他レベルを使って文側で対処する必要があります。
• 更新喪失:別のトランザクションにより更新が行われた後、その更新が検知されないまま、
トランザクションが同じデータに対して上書きを行ってしまうことを言います。
• ダーティ読み取り:別のトランザクションにより変更が加えられ、その変更がコミットされ
ていないのに、トランザクションが読み取りを実行してしまうことを言います。
• 再現不能読み取り:あるトランザクションにより、行の更新や削除が行われている間に、別
のトランザクションが何回も読み取りを行ってしまうことを言います。つまり、読み取り
データはそのつど変わることになります。READ COMMITTED では、性質上、この問題に
は対処できません。これは、READ COMMITTED が指定されているトランザクションでは、
他のトランザクションによる削除が許容されているためです。
• ファントム行:別のトランザクションにより複数行の更新が行われた後、トランザクション
の読み取りで行の取りこぼし(ファントム行)が出ることを言います。READ COMMITTED
では、性質上この問題には対処できません。
• 更新副作用:行では、通常、各値が相互に依存していますが、行によっては値同士の関連性
がロックやトリガー、整合性制約によって適宜保護または確立されていないことがありま
す。このような行に対して、複数のトランザクションによって同時にアクセスや更新が行
われ、そのアクセスや更新が不規則に繰り返し実行された場合、行の不整合を起こすこと
があります。これを更新副作用と呼んでいます。上のように、同一のデータに対して同時
に不規則に繰り返しアクセスするトランザクションは、トランザクション間のトランザク
ションと呼ばれます。
この 5 つの問題については、3 種類の排他レベルを使って対処することができます。なお、
READ COMMITTED に関しては、前述のように制限があります。次の表は、いずれかの排
他レベルが設定されているトランザクションについて、そのトランザクションがアクセス
する行やテーブルに対して、別のトランザクションからどのような処理が可能になるかを、
上記の問題に関連させながら示したものです。
第 4 章 トランザクションの操作
4-11
名前付きトランザクションの起動
表 4.5
InterBase でのトランザクションの競合の管理
問題
SNAPSHOT または READ COMMITTED
SNAPSHOT TABLE STABILITY
更新喪失
このトランザクションにより更新された行に
対しては、他のトランザクションからの更新は
できません。
このトランザクションにより制御されるテー
ブルに対しては、他のトランザクションからの
更新はできません。
ダーティ読み取り
このトランザクションによって更新された行
に対しては、 SNAPSHOT が設定されている
別のトランザクションから、更新前の行の読み
取りだけを行うことができます。
このトランザクションによって更新される
テーブルに対しては、他のトランザクションか
らアクセスできません。
このトランザクションによって行われた更新
に対しては、 READ COMMITTED が設定さ
れている別のトランザクションから、更新前の
データまたはコミット済みのデータの読み取
りだけを行うことができます。
SNAPSHOT(または SNAPSHOT
TABLE
STABILITY)が設定されているトランザク
SNAPSHOT(または SNAPSHOT
ションでは、そのトランザクションの起動時に
コミット済みだった行だけが読み取り可能で
す。したがって、SNAPSHOT のトランザクショ
ンでは再現不能読み取りは起こりません。
ションでは、そのトランザクションの起動時に
コミット済みだった行だけが読み取り可能で
す。したがって、SNAPSHOT のトランザクショ
ンでは再現不能読み取りは起こりません。
一方、 READ COMMITTED が設定されてい
るトランザクションでは、読み取りデータが変
化することを前提としなければなりません。
このトランザクションによって更新される
テーブルに対しては、他のトランザクションか
らアクセスできません。
ファントム行
READ COMMITTED が設定されているトラ
ンザクションでは、ファントム行が起こること
があります。
このトランザクションにより制御されるテー
ブルに対しては、他のトランザクションからア
クセスできません。
更新副作用
このトランザクションにより更新された行に
対しては、SNAPSHOT が設定されている別の
トランザクションからは、更新前の行の読み取
りだけが可能です。
このトランザクションにより制御されるテー
ブルに対しては、他のトランザクションからの
更新はできません。
再現不能読み取り
このトランザクションによって行われた更新
に対しては、 READ COMMITTED が設定さ
れている別のトランザクションから、更新前の
データまたはコミット済みのデータの読み取
りだけを行うことができます。
TABLE
STABILITY)が設定されているトランザク
トランザクション間のトランザクションにつ
いては、トリガーや整合性制約を使って問題を
回避する必要があります。
トランザクション間のトランザクションにつ
いては、トリガーや整合性制約を使って問題を
回避する必要があります。
SNAPSHOT または READ COMMITTED の選択
排他レベルとして SNAPSHOT と READ COMMITTED のどちらを選択するかは、アプリ
ケーションの内容によって異なります。InterBase では、SNAPSHOT がデフォルトの排他レ
ベルとなっています。READ COMMITTED もおよそ動作は同じです。ただし、SNAPSHOT
とは異なり、他のトランザクションによる更新は、そのコミット後に、順次読み取りが可
能になります。このため、READ COMMITTED を使用することで、通常、データの競合を
減らすことができます。
4-12 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
SNAPSHOT では、そのトランザクションの起動時に使用されたデータベースのビューがそ
のまま維持されます。これに対して、READ COMMITTED が設定されているトランザク
ションでは、起動後、他のトランザクションによる行の更新があった場合、そのコミット
直後に行の読み取り(つまり、最新の行の読み取り)が可能になります。どのトランザク
ションでも、SELECT 文を使用できます。ただし、次のような状況では SELECT による読み
取りは実行できません。
• アクセス対象のテーブルに対して、SNAPSHOT TABLE STABILITY が設定されている別の
トランザクションによって更新が実行され、そのテーブルがロックされている場合。
• 別のトランザクションにより挿入が実行され、その挿入がコミットされていない場合。 こ
の場合、SELECT は使用できますが、挿入された行の読み取りはできません。
要するに、READ COMMITTED が設定されているトランザクションでは、他のトランザク
ションによって更新された行をコミット直後に読み取ることができます。一方、
SNAPSHOT が設定されているトランザクションでは、起動後に行が更新された場合でも、
その更新の前の行(つまり、起動時に使用されたデータベースの行)の読み取りだけが可
能です。
SNAPSHOT、READ COMMITTED のどのトランザクションでも、アクセスモードが READ
WRITE の場合は、INSERT、UPDATE、DELETE を使用できます。ただし、SNAPSHOT TABLE
STABILITY が設定されているトランザクションによってテーブルがロックされている場合
は、この限りではありません。
SNAPSHOT トランザクションでは、処理対象の行のうち、すでに他のトランザクションに
よって更新または削除が実行され、その更新や削除がコミット済みの行に対しては、新た
な更新や削除は実行できません。このような更新、削除が行われた行に対して、SNAPSHOT
トランザクションにより再度更新が試みられたときは、更新競合エラーが発生します。
一方、READ COMMITTED と READ WRITE が設定されているトランザクションでは、他の
トランザクションによって変更された行もコミット後に読み取りが可能ですし、その後、こ
のような行に対してさらに更新を実行することもできます。
なお、同一の行に対して、SNAPSHOT と READ COMMITTED の両方のトランザクション
により同時に更新が実行されることがあります。このような場合、更新競合が発生するこ
とがあります。競合が起こった場合、次のような結果が予想されます。
• 大量更新または検索更新:つまり、1 つの UPDATE によりテーブルの複数行が処理される
更新では、競合が発生した時点で、それまでの更新は全部取り消されます。この場合、
UPDATE の再実行は可能です。なお、READ COMMITTED トランザクションでは、NO
RECORD_VERSION を指定することで、正しい読み取り結果に基づいた更新または削除が
可能になります。詳細は、4-14 ページの「排他レベルとして READ COMMITTED を使
用する場合のトランザクションの起動」を参照してください。
• カーソル更新または位置指定更新:つまり、行の集合から一度に 1 行ずつ取り出されて更
新が行われるような場合、競合の発生時には 1 行だけが無効になります。この場合、更新を
再開するには、カーソルをいったん閉じた後で再び開いて、競合が発生した箇所から更新
を再開します。
カーソルによる UPDATE の詳細は、第 6 章「データ処理」を参照してください。
第 4 章 トランザクションの操作
4-13
名前付きトランザクションの起動
排他レベルとして SNAPSHOT を使用する場合のトランザクションの起動
InterBase では、SNAPSHOT が排他レベルのデフォルトとなっています。したがって、排他
レベルとして SNAPSHOT を使用する場合、SET TRANSACTION で特に指定する必要はあ
りません。たとえば、次の 2 つの文は、いずれも同じになります。どちらも、t1 というトラ
ンザクションをアクセスモードとして READ WRITE を、排他レベルとして SNAPSHOT を
使って起動する例です。
EXEC SQL
SET TRANSACTION NAME t1;
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE SNAPSHOT;
なお、排他レベルは、アクセスモードおよびロック対応(記述されている場合)の次に付
加しなければなりません。
ヒント
排他モードは、デフォルトの SNAPSHOT を使用する場合であっても、指定することが理想
的なプログラミング方法です。これにより、アプリケーションのソースコードが読みやすく
なり、デバッグもしやすくなります。プログラムの意図は明確に記述するのが原則です。
排他レベルとして READ COMMITTED を使用する場合のトランザクションの起動
排他レベルとして READ COMMITTED を使用する場合は、この排他レベルを必ず指定しな
ければなりません。たとえば、次の文は、t1 というトランザクションを、アクセスモードと
して READ WRITE を、排他レベルとして READ COMMITTED を使って起動する例です。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE READ COMMITTED;
排他レベルは、必ずアクセスモードの次に記述しなければなりません。アクセスモードデ
フォルトで省略する場合は、排他レベルはトランザクション名に続けて記述します。
READ COMMITTED では、RECORD_VERSION と NO RECORD_VERSION という 2 種類の
パラメータを付加することもできます。このパラメータは両方同時に使用することはでき
ません。この 2 種類のパラメータを使用して、READ COMMITTED トランザクションがコ
ミットされていない行にアクセスした場合の動作を指定することができます。
• RECORD_VERSION を指定した場合、必ず最後にコミットされた行に対して読み取りが行
われます。それより新しい、コミットされていない行がディスクに格納されている場合も
同じです。
• NO RECORD_VERSION を指定した場合、最後にコミットされた行ではなく、コミットさ
れていなくても、要求された最も最後の行に対して読み取りが行われます。この NO
RECORD_VERSION がデフォルトとなっています。なお、ロック対応として WAIT を指定
しているときは、いったん待機状態に入り、コミットされていない最も最後の行がコミッ
トまたはロールバックされてから、再度読み取りを実行します。NO WAIT がオプションと
して指定されている場合は、トランザクションからただちにデッドロックエラーが報告さ
れます。
上 の 2 つ の パ ラ メ ー タ のうち、NO RECORD_VERSION はデフォルトなので、READ
COMMITTED で特に指定する必要はありません。たとえば、次の 2 つの文の内容は同じで
す。いずれも、t1 というトランザクションを、アクセスモードとして READ WRITE、排他
レベルとして READ COMMITTED、パラメータとして NO RECORD_VERSION を使って起
動します。
4-14 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE READ COMMITTED;
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE READ COMMITTED
NO RECORD_VERSION;
一方、RECORD_VERSION を使用する場合は、必ず文中に指定しなければなりません。たと
えば、t1 というトランザクションを、アクセスモードとして READ WRITE、排他レベルと
して READ COMMITTED、パラメータとして RECORD_VERSION を使って起動する場合、
次のように記述します。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE READ COMMITTED
RECORD_VERSION;
排他レベルとして SNAPSHOT TABLE STABILITY を使用する場合の
トランザクションの起動
排他レベルとして SNAPSHOT TABLE STABILITY を使用する場合は、この排他レベルを必
ず指定しなければなりません。次の文は、t1 というトランザクションを、アクセスモードと
して READ WRITE、排他レベルとして SNAPSHOT TABLE STABILITY を使って起動する例
です。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE SNAPSHOT TABLE STABILITY;
排他レベルは、アクセスモードおよびロック対応(指定されている場合)の次に付加しな
ければなりません。
重要
SNAPSHOT TABLE STABILITY の使用には注意が必要です。この排他レベルを指定した場
合、複数のトランザクションが同一のデータベースにアクセスする環境では、ロック競合
の発生の可能性が非常に高くなります。
排他レベルの相互作用
2 つのトランザクションにより同一のデータベースにアクセスが行われたときは、ロックの
競合が起こることがあります。この場合、2 つのトランザクションに設定されている排他レ
ベルおよびアクセスモードを考慮してみる必要があります。次の表に、競合が発生する可能
性がある組み合わせを示します。
表 4.6
排他レベルと SELECT および UPDATE との関係
SNAPSHOT または
READ COMMITTED
SNAPSHOT または
READ
COMMITTED
SNAPSHOT
TABLE
STABILITY
SNAPSHOT TABLE STABILITY
UPDATE
SELECT
UPDATE
SELECT
UPDATE
同時に更新が実行されると
競合する可能性がある
—
必ず競合
必ず競合
SELECT
—
—
—
—
UPDATE
必ず競合
—
必ず競合
必ず競合
SELECT
必ず競合
—
必ず競合
—
第 4 章 トランザクションの操作
4-15
名前付きトランザクションの起動
上の表に示すように、排他レベルで見ると、トランザクションは SNAPSHOT と READ
COMMITTED の組み合わせで最も競合の可能性が薄くなります。たとえば、t1 がアクセス
モードが READ WRITE の SNAPSHOT のトランザクションで、t2 がアクセスモードが
READ WRITE の READ COMMITTED のトランザクションとすると、2 つのトランザクショ
ンが同一の行に対して更新した場合にのみ競合が起こることになります。さらに、t1 と t2
のトランザクションのアクセスモードが READ ONLY の場合、競合は一切発生しません。
また、アクセスモードが READ WRITE の SNAPSHOT TABLE STABILITY のトランザクショ
ンでは、そのトランザクションだけであればテーブルの更新が可能ですが、同時に動作す
るトランザクションが他にあれば、そのトランザクションと競合を生じます。ただし、ア
クセスモードが READ ONLY の SNAPSHOT または READ COMMITTED のトランザクショ
ンであれば競合は起こりません。また、アクセスモードが READ ONLY の SNAPSHOT
TABLE STABILITY のトランザクションでは、他の READ ONLY のトランザクションとの競
合は起こりませんが、他のトランザクションがデータの挿入、更新、削除を実行するもの
であれば競合が生じます。
ロック対応
トランザクションの実行の際に、ロックの競合が起こることがありますが、ロック対応で
は、その場合の対応処置を指定することができます。ロック対応で指定できる対応措置は次
の 2 とおりです。
• WAIT:デフォルト。WAIT を指定しておくと、リソース(行やテーブル)がロックされて
いる場合、トランザクションはいったん待機状態に入ります。この後、リソースが解放さ
れると、再度処理が行われます。
• NO WAIT:NO WAIT を記述しておくと、ロックを見つけた場合、ロックの競合エラーが
報告されます。ロックの解放まで待機することはありません。
WAIT はデフォルトなので、SET TRANSACTION で明示的に記述する必要はありません。し
たがって、次の 2 つの文の意味は同じです。どちらの文でも、t1 というトランザクション
が、アクセスモードとして READ WRITE、ロック対応として WAIT、排他レベルとして
READ COMMITTED を使って起動されます。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE READ COMMITTED;
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE WAIT READ COMMITTED;
一方、NO WAIT を使用する場合は、SET TRANSACTION で明示的に指定しなければなりま
せん。たとえば、t1 というトランザクションを、アクセスモードとして READ WRITE、ロッ
ク対応として NO WAIT、排他レベルとして SNAPSHOT を使って起動する場合は、次のよ
うに記述します。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE NO WAIT READ SNAPSHOT;
なお、ロック対応を指定するときは、アクセスモードと排他レベルの間に記述します。
ヒント
ロック対応は、デフォルトの WAIT を使用する場合であっても、指定することが理想的な
プログラミング方法です。これにより、アプリケーションのソースコードが読みやすくな
り、デバッグもしやすくなります。プログラムの意図は明確に記述するのが原則です。
4-16 埋 め 込 み S Q L ガ イ ド
名前付きトランザクションの起動
RESERVING 句
SET TRANSACTION には、RESERVING 句を付加することもできます。この RESERVING 句
を使用して、そのトランザクションで使用するテーブルを予約することができます。この
結果、他のトランザクションからのアクセスは制限されることになります。RESERVING で
は、トランザクションの起動時にテーブルの予約が行われます。この点で、そのつどテー
ブルの指定が必要なデータ操作文とは異なります。RESERVING は、通常、同一のデータ
ベースに対して複数のトランザクションからアクセスされる環境で有効です。RESERVING
の使用には、主に次の 3 つの利点があります。
• 処理中、特に必要な場合にロックが起こり、このためデッドロック(処理停止)や更新競
合が発生することがありますが(デフォルトの動作)
、このような更新競合などを防ぐこと
ができます。
• トリガーや整合性制約により複数のテーブルにロックがかけられることがありますが、こ
のロックを従属性ロック(dependency locking)と呼んでいます。RESERVING では、この従
属性ロックを強化する働きがあります。この従属性ロックは、特に明示的に保護する必要
はありませんが、それでも RESERVING を使用することにより、テーブルの間接競合から
起こる更新競合を防ぐことができます。
• トランザクションで使用するテーブルについて、他のトランザクションからのアクセスの
レベル(処理の内容)を限定することができます。たとえば、READ WRITE SNAPSHOT の
トランザクションを起動し、そのトランザクションでのみ 1 つのテーブルに対する更新を
行う場合、RESERVING 句を使用することによって、他のトランザクションからは、その
テーブルに対して更新ができなくなるようにすることができます。
重要
SET TRANSACTION 文では、RESERVING 句または USING 句のどちらか一方しか設定でき
ません。テーブルを予約してトランザクションを実行するには、SET TRANSACTION 構文
を使用します。
EXEC SQL
SET TRANSACTION [NAME name]
[READ WRITE| READ ONLY]
[WAIT | NO WAIT]
[[ISOLATION LEVEL] {SNAPSHOT [TABLE STABILITY]
| READ COMMITTED [[NO] RECORD_VERSION]}]
RESERVING <reserving_clause>;
<reserving_clause> = table [, table ...]
[FOR [SHARED | PROTECTED] {READ | WRITE}] [, <reserving_clause>]
第 4 章 トランザクションの操作
4-17
名前付きトランザクションの起動
RESERVING 句でテーブルを複数予約するときは、同じテーブル名を記述しないようにしま
す。また、テーブル名はカンマで区切って並べます。テーブル名の後ろには、その予約のオ
プション(PROTECTED READ など、他のトランザクションで可能な処理内容)を記述し
ます。RESERVING 句で指定できるオプションと処理内容は次の表のとおりです。
表 4.7
RESERVING 句を使用したテーブル予約のオプション
予約オプション
用途
PROTECTED
READ
予約したテーブルの行に対しては、他のトランザクションによる更新はできま
せん。テーブルの読み取りは、どのトランザクションから行うこともできます。
PROTECTED
WRITE
予約したテーブルの行に対しては、他のトランザクションによる更新はできま
せん。
SNAPSHOT または READ COMMITTED が設定されているトランザクショ
ンからテーブルの読み取りは可能ですが、更新はできません。
SHARED READ
どのトランザクションからでも、テーブルの読み取りが可能です。READ
WRITE が設定されているトランザクションからは、テーブルの更新が可能で
す。この SHARED READ が、最も解放されたモードです。
SHARED WRITE
SNAPSHOT または READ COMMITTED のトランザクションのうち、アク
セスモードが READ WRITE のトランザクションからは、テーブルの更新が可能
です。SNAPSHOT または READ COMMITTED のトランザクションでは、
テーブルの読み取りが可能です。
たとえば、トランザクション名が t1、アクセスモードとして READ WRITE、排他レベルと
して SNAPSHOT という設定で、EMPLOYEE というテーブルを予約する場合、次の文のよ
うになります。ここでは、予約オプションとして PROTECTED WRITE を指定しています。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE WAIT SNAPSHOT
RESERVING EMPLOYEE FOR PROTECTED WRITE;
また、トランザクション名が t1、アクセスモードとして READ WRITE、排他レベルとして
READ COMMITTED という設定で、EMPLOYEES、EMP_PROJ という 2 つのテーブルを予約
する場合、次の文のようになります。ここでは、予約オプションとして、EMPLOYEES に
は SHARED WRITE を、EMP_PROJ には PROTECTED WRITE をそれぞれ指定しています。
EXEC SQL
SET TRANSACTION NAME t1 READ WRITE WAIT READ COMMITTED
RESERVING EMPLOYEES FOR SHARED WRITE, EMP_PROJ
FOR PROTECTED READ;
SNAPSHOT または READ COMMITTED のトランザクションに RESERVING を加えること
で、テーブルを予約し、そのテーブルに対して別のトランザクションから同時にアクセス
することを制限することができます。また、SNAPSHOT TABLE STABILITY のトランザク
ションでは、RESERVING を使用することにより、競合などが起こった場合のデッドロック
の発生率を低くすることができます。
USING 句
SET TRANSACTION によりトランザクションが起動されるたびに、その時点で開かれてい
るデータベース全部にシステムリソースが割り当てられます。このような場合、USING 句
を使用して、トランザクションのアクセス対象となるデータベースの数を限定し、システ
4-18 埋 め 込 み S Q L ガ イ ド
データ操作文でのトランザクション名の扱い
ムリソースを節約することができます。つまり、USING を記述することで、開かれている
データベースのうち、指定したデータベースのテーブルだけにアクセスが行われるように
なります。USING の構文は次のとおりです。
EXEC SQL
SET TRANSACTION [NAME name]
[READ WRITE | READ ONLY]
[WAIT | NO WAIT]
[[ISOLATION LEVEL] {SNAPSHOT [TABLE STABILITY]
| READ COMMITTED [[NO] RECORD_VERSION]}]
USING dbhandle> [, dbhandle ...];
重要
SET TRANSACTION 文では、1 つの文につき、RESERVING 句または USING 句のどちらか
しか設定できません。
次の C のコード例では、test.ib、research.ib、employee.ib という 3 つのデータベースにそれぞ
れ TEST、RESEARCH、EMP というデータベースハンドルを設定して開いています。その
後、デフォルトトランザクションを起動するとともに、USING を使ってアクセス対象のデー
タベースを TEST と EMP の 2 つに限定しています。
. . .
EXEC SQL
SET DATABASE ATLAS = 'test.ib';
EXEC SQL
SET DATABASE RESEARCH = 'research.ib';
EXEC SQL
SET DATABASE EMP = 'employee.ib';
EXEC SQL
CONNECT TEST, RESEARCH, EMP; /* すべてのデータベースを開きます */
EXEC SQL
SET TRANSACTION USING TEST, EMP;
. . .
データ操作文でのトランザクション名の扱い
名前付きトランザクションの起動後は、INSERT、UPDATE、DELETE、OPEN の各データ操
作文で、その名前を使用することができます。トランザクション名を指定した文は、以後、
そのトランザクションに制御されるとともに、関連して機能することになります。たとえ
ば、次の C コードでは、mytrans1 と mytrans2 という 2 つのトランザクションハンドルを宣
言するとともに、ハンドルを 0 に初期化した後、この 2 つのトランザクションを起動して
います。次に、INSERT と OPEN で各トランザクションを指定しています。以後、INSERT
と OPEN はいずれも、指定したトランザクションと関連して動作することになります。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
long *mytrans1, *mytrans2;
char city[26];
第 4 章 トランザクションの操作
4-19
データ操作文でのトランザクション名の扱い
EXEC SQL
END DECLARE SECTION;
mytrans1 = 0L;
mytrans2 = 0L;
. . .
EXEC SQL
SET DATABASE ATLAS = 'atlas.ib';
EXEC SQL
CONNECT;
EXEC SQL
DECLARE CITYLIST CURSOR FOR
SELECT CITY FROM CITIES
WHERE COUNTRY = 'Mexico';
EXEC SQL
SET TRANSACTION NAME mytrans1;
EXEC SQL
SET TRANSACTION mytrans2 READ ONLY READ COMMITTED;
. . .
printf('Mexican city to add to database: ');
gets(city);
EXEC SQL
INSERT TRANSACTION mytrans1 INTO CITIES (CITY, COUNTRY)
VALUES :city, 'Mexico';
EXEC SQL
COMMIT mytrans1;
EXEC SQL
OPEN TRANSACTION mytrans2 CITYLIST;
EXEC SQL
FETCH CITYLIST INTO :city;
while (!SQLCODE)
{
printf("%s¥n", city);
EXEC SQL
FETCH CITYLIST INTO :city;
}
EXEC SQL
CLOSE CITYLIST;
EXEC SQL
COMMIT;
EXEC SQL
DISCONNECT;
. . .
4-20 埋 め 込 み S Q L ガ イ ド
トランザクションの終了
上の例に示すように、DECLARE CURSOR 文にはトランザクション名を記述しません。トラ
ンザクション名は、宣言したカーソルの OPEN 文に記述します。これで、宣言したカーソ
ルとトランザクション名が関連付けられます。宣言したカーソルに関連する後続の FETCH
文と CLOSE 文には、トランザクション名の指定は不要です。
メモ
トランザクション名は、DSQL の EXECUTE と EXECUTE IMMEDIATE の各ステートメント
でも使用できます。
データ操作文でトランザクション名を使用する方法の詳細は、第 6 章「データ処理」を参
照してください。トランザクション名と COMMIT 文の詳細は、4-22 ページの「COMMIT
の使い方」を参照してください。DSOL 文でトランザクション名を使用する方法の詳細は、
4-29 ページの「DSQL での複数のトランザクションの使い方」を参照してください。
トランザクションの終了
トランザクションで行うタスクが全部終了したとき、または、エラーが発生してタスクの
完了が不可能になった場合は、トランザクションを終了する必要があります。これにより、
データベースは通常の状態に戻ります。トランザクションは、次の 2 つの文を使って終了す
ることができます。
• COMMIT:この文では、トランザクションで実行された変更がデータベースに保存されま
す。つまり、トランザクションでの全処理が無事に終了したことがシステムに報告されま
す。
• ROLLBACK:この文では、トランザクションによる変更が取り消され、データベースはト
ランザクションが起動する前の状態に戻ります。この ROLLBACK は、通常、なんらかのエ
ラーが発生し、トランザクションによるタスクの完了が不可能な場合に使用します。
COMMIT でも ROLLBACK でも、現在起動されているトランザクションに関係するレコー
ドストリームが閉じられます。また、トランザクション名が 0 に初期化されるとともに、そ
のトランザクションに割り当てられていたシステムリソースが解放されます。解放された
システムリソースは、この後、アプリケーションやプログラムに利用されることになりま
す。
COMMIT や ROLLBACK の利用には、この他にも利点があります。つまり、これらの文によ
り、プログラムの論理構成や意図が明確になり、プログラムも読みやすくなります。また、
何より、プログラマは、トランザクションによる変更が意図したとおりに処理されている
かどうかをその記述から判断することができます。
ROLLBACK は、通常、エラー発生時にトランザクションを終了処理するための内部エラー
処理ルーチンに使用されます。また、なんらかの理由でトランザクションの処理が完了しな
かった場合、処理の再実行に先立ってロールバックする場合にも利用できます。さらに、プ
ログラムが復旧不能なエラーに陥ったときに、データベースを元の状態に復元する目的で
使用することもできます。
重要
プログラムがトランザクションの終了の前に終了したときは、トランザクションの処理は
自動的にロールバックされます。ただし、データベースは自動的に閉じることはありませ
ん。このように、データベースが閉じられないままプログラムが終了してしまうと、データ
の損失や破損が起こることがあります。このため、開かれているデータベースは、必ず、
DISCONNECT、COMMIT RELEASE、ROLLBACK RELEASE 文を使用して、事前に閉じてお
かなければなりません。
第 4 章 トランザクションの操作
4-21
トランザクションの終了
DISCONNECT、COMMIT RELEASE、および ROLLBACK RELEASE の詳細は、第 3 章「デー
タベースの操作」を参照してください。
COMMIT の使い方
COMMIT を使用して、それまでのトランザクションによる変更をデータベースに保存する
ことができます。
COMMIT を実行すると、トランザクションに関連するレコードストリームが閉じられると
同時に、トランザクション名が 0 に初期化されます。また、トランザクションに割り当て
られていたシステムリソースが解放され、他の目的に利用できるようになります。COMMIT
の正規の構文は次のとおりです。
EXEC SQL
COMMIT [TRANSACTION name] [RETAIN [SNAPSHOT] | RELEASE dbhandle
[, dbhandle ...]]
たとえば、次の C コードは、1 つのトランザクションが終了するまでの例です。このコード
では、1993 年 1 月 1 日より前に入社した従業員全員に対して、生活費の上昇を補填するた
め 4.3% の賃金アップを行っています。条件に合致した従業員のレコードの更新が無事終了
した場合、トランザクションがコミットされ、変更がデータベースに記録されます。この
変更は、データベースにも実際に記録されます。
. . .
EXEC SQL
SET TRANSACTION SNAPSHOT TABLE STABILITY;
EXEC SQL
UPDATE EMPLOYEE
SET SALARY = SALARY * 1.043
WHERE HIRE_DATE < '1-JAN-1993';
EXEC SQL
COMMIT;
. . .
なお、COMMIT でトランザクション名を指定しなかったときは、COMMIT はデフォルトト
ランザクションである GDS__TRANS に対して働きます。したがって、デフォルトトランザ
クション以外のトランザクションによる処理をコミットする場合は、そのトランザクショ
ン名をパラメータとして指定します。
ヒント
アクセスモードが READ ONLY のトランザクションでは、データベースの変更は行われま
せんが、トランザクションの終了には ROLLBACK ではなく COMMIT を使用してください。
これは、COMMIT の方が、次のトランザクションを起動する際のオーバーヘッドが大幅に
少なくて済むためです。
トランザクション名の指定
デフォルトトランザクションの処理をコミットする場合は COMMIT にトランザクション
名の指定は不要ですが、それ以外のときは COMMIT にトランザクション名を記述しなけれ
ばなりません。たとえば、次は、名前を使って 2 つのトランザクションを起動し、各トラン
ザクションによる変更をコミットする C のコードです。
. . .
4-22 埋 め 込 み S Q L ガ イ ド
トランザクションの終了
EXEC SQL
BEGIN DECLARE SECTION;
isc_tr_handle TR1, TR2;
EXEC SQL
END DECLARE SECTION;
TR1 = (isc_tr_handle) NULL;
TR2 = (isc_tr_handle) NULL;
. . .
EXEC SQL
SET TRANSACTION NAME TR1;
EXEC SQL
SET TRANSACTION NAME TR2;
. . .
/* 実際の処理を行います */
. . .
EXEC SQL
COMMIT TRANSACTION TR1;
EXEC SQL
COMMIT TRANSACTION TR2;
. . .
重要
複数のトランザクションを使用するプログラムでは、COMMIT には必ずトランザクション
名を記述しなければなりません。ただし、デフォルトトランザクションをコミットする場
合は、記述する必要はありません。
トランザクションを解放しないコミット
ときは、トランザクションによる変更を保存した後でも、現在のトランザクションのスナッ
プショットを解除したくない場合もあります。このような場合、COMMIT に RETAIN オプ
ションを付加します。COMMIT RETAIN を使用すると、作業がコミットされ新しいトラン
ザクションが開かれます。このとき、これまでのトランザクションのスナップショットは
維持されます。特に、複数のユーザー環境で使用するような負荷の大きいシステムで使用す
る場合に、これまでのスナップショットが維持されると、処理速度の向上につながります。
また、トランザクションを終了し、別のトランザクションを起動する場合に比べて、シス
テムリソースの消費も節約できます。ただし、他のユーザーからのアクセスが保留されてい
てもわからないというのが COMMIT に RETAIN を付加した場合の欠点です。
RETAIN の構文は、次のようになります。
EXEC SQL
COMMIT [TRANSACTION name] RETAIN [SNAPSHOT];
ヒント
Delphi などのツールで BDE を使用している場合にこの機能が必要なときは、BDE 環境設定
で「soft commit」を指定してください。
たとえば、次の例は、CITIES テーブルの POPULATION 列の値を更新するための C 言語の
コードです。国名と人口増加割合は、いずれもユーザーが入力します。コードでは、行が更
新されるたびに、RETAIN 付きの COMMIT が実行され、現在のカーソルとシステムリソー
スが維持されます。
. . .
第 4 章 トランザクションの操作
4-23
トランザクションの終了
EXEC SQL
BEGIN DECLARE SECTION;
char country[26], city[26], asciimult[10];
int multiplier;
long pop;
EXEC SQL
END DECLARE SECTION;
. . .
main ()
{
EXEC SQL
DECLARE CHANGEPOP CURSOR FOR
SELECT CITY, POPULATION
FROM CITIES
WHERE COUNTRY = :country;
printf("Enter country with city populations needing adjustment: ");
gets(country);
EXEC SQL
SET TRANSACTION;
EXEC SQL
OPEN CHANGEPOP;
EXEC SQL
FETCH CHANGEPOP INTO :city, :pop;
while(!SQLCODE)
{
printf("City: %s Population: %ld¥n", city, pop);
printf("¥nPercent change (100%% to -100%%:");
gets(asciimult);
multiplier = atoi(asciimult);
EXEC SQL
UPDATE CITIES
SET POPULATION = POPULATION * (1 + :multiplier / 100)
WHERE CURRENT OF CHANGEPOP;
EXEC SQL
COMMIT RETAIN; /* 変更をコミットし、現在の状態を保存します */
EXEC SQL
FETCH CHANGEPOP INTO :city, :pop;
if (SQLCODE && (SQLCODE != 100))
{
isc_print_sqlerror(SQLCODE, isc_$status);
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT;
exit(1);
4-24 埋 め 込 み S Q L ガ イ ド
トランザクションの終了
}
}
EXEC SQL
COMMIT;
EXEC SQL
DISCONNECT;
}
メモ
なお、COMMIT RETAIN の後に ROLLBACK を実行した場合、その COMMIT RETAIN の後
に実行された更新と書き込みだけが ROLLBACK によりロールバックされます。
重要
複数のトランザクションを扱うプログラムでは、COMMIT RETAIN でも必ずトランザクショ
ン名を指定しなければなりません。ただし、トランザクションがデフォルトの場合は、その
必要はありません。トランザクション名の詳細は、4-5 ページの「トランザクションの命名」
を参照してください。
ROLLBACK の使い方
ROLLBACK を使用して、トランザクションが起動する前の状態にデータベースを復元する
ことができます。また、ROLLBACK では、トランザクションに関連するレコードストリー
ムを閉じたり、トランザクション名の 0 への初期化、トランザクションに割り当てられて
いるシステムリソースの解放といった処理も実行されます。ROLLBACK は、通常、エラー
処理ルーチンで使用します。ROLLBACK の構文は次のとおりです。
EXEC SQL
ROLLBACK [TRANSACTION name] [RELEASE [dbhandle [, dbhandle ...]]];
次の C コードは、1 つのトランザクションが終了するまでの例です。このコードでは、1993
年 1 月 1 日より前に入社した従業員全員に対して、生活費の上昇を補てんするため 4.3% の
賃金アップを行います。条件に合致した従業員のレコードの更新が無事終了した場合、トラ
ンザクションがコミットされ、変更がデータベースに記録されます。また、エラーが発生し
たときは、トランザクションによる変更はすべて取り消され、データベースはトランザク
ションの起動前の状態に復元します。
. . .
EXEC SQL
SET TRANSACTION SNAPSHOT TABLE STABILITY;
EXEC SQL
UPDATE EMPLOYEES
SET SALARY = SALARY * 1.043
WHERE HIRE_DATE < '1-JAN-1993';
if (SQLCODE && (SQLCODE != 100))
{
isc_print_sqlerror(SQLCODE, isc_$status);
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT;
exit(1);
}
第 4 章 トランザクションの操作
4-25
複数のトランザクションの使い方
EXEC SQL
COMMIT;
EXEC SQL
DISCONNECT;
. . .
なお、ROLLBACK でトランザクション名を指定しなかったときは、ROLLBACK はデフォ
ルトトランザクションである GDS__TRANS に対して働きます。したがって、デフォルトト
ランザクション以外のトランザクションによる処理をロールバックする場合は、そのトラ
ンザクション名を ROLLBACK のパラメータとして指定します。
複数のトランザクションの使い方
InterBase では複数のトランザクション名が扱えるため、プログラムで同時に複数のトラン
ザクションを起動し、各トランザクションに個別に処理を実行させることができます。この
場合、トランザクション名はそれぞれ別でなければなりません。これは、複数のトランザク
ションが同時に機能する場合、その名前により識別されるためです。トランザクション名は
また、データ操作文やトランザクション操作文で使用することもできます。これらの文で
トランザクション名を指定した場合、その文は指定したトランザクションと関連して機能
することになります。トランザクション名の宣言と使用の詳細は、4-4 ページの「名前付き
トランザクションの起動」を参照してください。
名前付きトランザクションをプログラムで使用するには、次のような手順があります。
1
トランザクション名を一意な変数で宣言します。トランザクションが複数のときは、名
前が重複しないようにします。
2
3
トランザクション名(変数)を 0 に初期化します。
SET TRANSACTION と有効なトランザクション名を使って各トランザクションを起動
します。
4
後続のデータ操作文やトランザクション操作文で、トランザクション名をパラメータと
して使って処理を行います。トランザクション名を指定した文は、そのトランザクショ
ンに制御されながら、関連して機能することになります。
デフォルトのトランザクション
複数のトランザクションを扱うプログラムでは、各トランザクションに対して名前を付け
ておくことが必要です。この場合、その複数のトランザクションの中にデフォルトトランザ
クション(GDS__TRANS)があってもかまいません。デフォルトトランザクションは必ず
しも SET TRANSACTION で起動する必要はありませんが、トランザクションが複数の場合
は、明示的に起動するのが理想的です。また、データ操作文でも名前を使って参照するよ
うにします。
4-26 埋 め 込 み S Q L ガ イ ド
複数のトランザクションの使い方
データ操作文やトランザクション操作文にトランザクション名が指定されていなかった場
合は、その文では自動的にデフォルトトランザクションが使用されます。また、デフォルト
トランザクションを SET TRANSACTION 文で明示的に起動していない場合は、前処理時に
gpre によりデフォルトトランザクション起動のための文が挿入されます。
重要
DSQL プログラムは、gpre -m スイッチを使って前処理を行わなければなりません。このス
イッチを付けた場合、デフォルトトランザクションの自動生成は行われず、エラーが報告
されます。DSQL では、デフォルトトランザクションを含め、使用するすべてのトランザク
ションを明示的に起動しておかなければなりません。
カーソルの扱い
DECLARE CURSOR ではトランザクション名を指定するはことはできません。そのかわり、
トランザクション名は、宣言したカーソルの OPEN 文のパラメータとして指定します。こ
れで、カーソルとトランザクションが関連付けられます。なお、カーソルに関連付けること
ができるトランザクションは 1 つに限られています。たとえば、次は、カーソルを宣言し、
その OPEN 文で T1 というトランザクションを関連付けているコード例です。
. . .
EXEC SQL
DECLARE S CURSOR FOR
SELECT COUNTRY, CUST_NO, SUM(QTY_ORDERED)
FROM SALES
GROUP BY CUST_NO
WHERE COUNTRY = 'Mexico';
EXEC SQL
SET TRANSACTION T1 READ ONLY READ COMMITTED;
. . .
EXEC SQL
OPEN TRANSACTION T1 S;
. . .
なお、OPEN 文にトランザクション名を指定しなかったときは、文はデフォルトトランザ
クション(GDS__TRANS)に関連付けられます。
OPEN 文によりトランザクションの関連付けが完了すると、後続のカーソル関連文も、そ
のトランザクションに自動的に関連付けられ、その制御のもとで機能します。このため、
カーソル関連文では、パラメータとしてトランザクション名を指定することはできません。
次は、t2 というトランザクションを OPEN 文で S というカーソルと関連付け、その後、カー
ソル S を FETCH と CLOSE で処理しているコード例です。
. . .
EXEC SQL
OPEN TRANSACTION t2 S;
EXEC SQL
FETCH S INTO :country, :cust_no, :qty;
while (!SQLCODE)
{
printf("%s %d %d¥n", country, cust_no, qty);
第 4 章 トランザクションの操作
4-27
複数のトランザクションの使い方
EXEC SQL
FETCH S INTO :country, :cust_no, :qty;
}
EXEC SQL
CLOSE S;
. . .
1 つのトランザクションで複数のカーソルを扱うこともでき、逆に、複数のトランザクショ
ンで 1 つのカーソルを制御することもできるので、必要に応じた柔軟な対応が可能です。
複数のトランザクションを使用する場合の処理例
複数のトランザクションを扱うプログラムの簡単な C のコード例を以下に示します。ここ
では、mytrans1 と mytrans2 という 2 つのトランザクションハンドルを宣言するとともに、ハ
ンドルを 0 に初期化した後、この 2 つのトランザクションを起動しています。その後、後
続のデータ操作文でトランザクション名を使って処理を行っています。データ操作文に
よっては、トランザクション名とともにカーソルを記述しているものもあります。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
long *mytrans1 = 0L, *mytrans2 = 0L;
char city[26];
EXEC SQL
END DECLARE SECTION;
. . .
EXEC SQL
DECLARE CITYLIST CURSOR FOR
SELECT CITY FROM CITIES
WHERE COUNTRY = 'Mexico';
EXEC SQL
SET TRANSACTION NAME mytrans1;
EXEC SQL
SET TRANSACTION mytrans2 READ ONLY READ COMMITTED;
. . .
printf("Mexican city to add to database: ");
gets(city);
EXEC SQL
INSERT TRANSACTION mytrans1 INTO CITIES
VALUES :city, 'Mexico', NULL, NULL, NULL, NULL;
EXEC SQL
COMMIT mytrans1;
EXEC SQL
OPEN TRANSACTION mytrans2 CITYLIST;
EXEC SQL
FETCH CITYLIST INTO :city;
while (!SQLCODE)
4-28 埋 め 込 み S Q L ガ イ ド
DSQL での複数のトランザクションの使い方
{
printf("%s¥n", city);
EXEC SQL
FETCH CITYLIST INTO :city;
}
EXEC SQL
CLOSE CITYLIST;
EXEC SQL
COMMIT mytrans2;
EXEC SQL
DISCONNECT
. . .
DSQL での複数のトランザクションの使い方
InterBase では、DSQL で複数のトランザクションを扱えるようになっています。ただし、こ
の場合、次のような制限があります。
• プログラムは、gpre -m スイッチを使って前処理を行わなければなりません。
• トランザクション名は、静的に宣言しなければなりません。 実行時に、ユーザーが変数を
使って定義することはできません。
• トランザクション名は、事前に 0 に初期化しておいてから DSQL 文で使用しなければなり
ません。
• トランザクションはすべて、SET TRANSACTION 文で明示的に起動しなければなりませ
ん。
• 埋め込みプログラムの場合、データ定義言語(DDL)は名前付きトランザクションの処理
部分では使用できません。DDL は、必ずデフォルトトランザクションである GDS__TRANS
との関連で使用しなければなりません。
• トランザクション名の記述のない SET TRANSACTION 文を使用して、実行時に、ユーザー
によるトランザクションの動作(アクセスモードやロック対応など)の変更が可能です。
この場合、PREPARE の後にトランザクション名を指定するとともに、後続の EXECUTE 文
でトランザクション名を指定することで、動作の変更が実行されます。PREPARE と
EXECUTE のほか、EXECUTE IMMEDIATE 文も使用できます。
InterBase では、どのプログラムでも、トランザクション名は前処理を行う際に固定されま
す。したがって、ユーザーが動的に割り当てることはできません。ただし、実行時、ユー
ザーが DSQL トランザクションの動作(アクセスモードやロック対応など)を変更するこ
とは可能です。なお、ユーザーによる動作の変更が予想される場合、プログラム上で相応の
処理を記述しておかなければなりません。次の節では、ユーザーによるトランザクション動
作の変更方法について説明します。
第 4 章 トランザクションの操作
4-29
DSQL での複数のトランザクションの使い方
“?” によるトランザクションの動作の変更
DSQL プログラムでは、使用できるトランザクションの名前と数は、InterBase のプリプロ
セッサである gpre で前処理を行った際に設定されます。したがって、DSQL 文で使用する
名前付きトランザクションは、事前にプログラマが決めておかなければなりません。また、
各トランザクションの動作も事前に決めておかなければなりません。このように、トランザ
クション名はユーザーが変更することはできませんが、トランザクションの動作について
は、実行時にユーザーが変更することができます。
DSQL プログラムでは、ユーザーが SQL 文を入力することができます。この文はホスト言
語の文字列変数として格納され、格納された変数は PREPARE 文または EXECUTE 文で処理
できます。また、この 2 つの文のかわりに、EXECUTE IMMEDIATE を使用することもでき
ます。
PREPARE
• 変数に代入されている文にエラーがないかどうかを確認します。
• 文を XSQLDA にロードし、後続の EXECUTE 文に渡します。
EXECUTE IMMEDIATE
• 文にエラーがないかどうかを確認します。
• 文を XSQLDA にロードします。
• 文を実行します。
EXECUTE も EXECUTE IMMEDIATE も、すでに SET TRANSACTION で起動されているトラ
ンザクションに関連して動作します。この場合、トランザクションは名前付きトランザク
ションでもデフォルトトランザクション(GDS__TRANS を指定)でもかまいません。なお、
トランザクション名を指定しなかったときは、EXECUTE または EXECUTE IMMEDIATE は
デフォルトトランザクション(GDS__TRANS)に対して機能します。
EXECUTE 文と EXECUTE IMMEDIATE 文のトランザクション動作を変更するには、次の 2
つが処理のポイントとなります。
• ユーザーに SET TRANSACTION 文の入力を要求し、入力を変数に格納します。
• SET TRANSACTION 文を使用して、事前に動作を変更するトランザクションを起動してお
きます。このトランザクションの動作が、後続の EXECUTE または EXECUTE IMMEDIATE
で変更されることになります。
起動済みのトランザクション(デフォルトまたは名前付き)の動作は、ユーザー入力の SET
TRANSACTION 文によって変更されることになります。この変更は、次の SET
TRANSACTION 文が実行されると無効になります。
次は、ユーザーにトランザクションの動作を変更するかどうかを尋ね、変更の指示があれ
ば実行に移す C のコードです。また、次のユーザー文では、変更後のトランザクションを
使って処理を行います。その後、トランザクションの動作を復元しています。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char usertrans[512], query[1024];
4-30 埋 め 込 み S Q L ガ イ ド
DSQL での複数のトランザクションの使い方
char deftrans[] = {"SET TRANSACTION READ WRITE WAIT SNAPSHOT"};
EXEC SQL
END DECLARE SECTION;
. . .
printf("¥nEnter SQL statement: ");
gets(query);
printf("¥nChange transaction behavior (Y/N)? ");
gets(usertrans);
if (usertrans[0] == "Y" || usertrans[0] == "y")
{
printf("¥nEnter ¥"SET TRANSACTION¥" and desired behavior: ");
gets(usertrans);
EXEC SQL
COMMIT usertrans;
EXEC SQL
EXECUTE IMMEDIATE usertrans;
}
else
{
EXEC SQL
EXECUTE IMMEDIATE deftrans;
}
EXEC SQL
EXECUTE IMMEDIATE query;
EXEC SQL
EXECUTE IMMEDIATE deftrans;
. . .
重要
上のコード例でもわかるように、動作中のトランザクションを必ずコミット(またはロー
ルバック)してから、SET TRANSACTION 文(EXECUTE IMMEDIATE)を実行しなければ
なりません。
第 4 章 トランザクションの操作
4-31
4-32 埋 め 込 み S Q L ガ イ ド
第
章
データ定義文
第5章
この章では、SQL アプリケーションでデータベースを作成、修正、削除する方法について
説明します。また、データベースのテーブル、ビュー、インデックスの作成、修正、削除
の方法についても説明しています。データベースは基本的にテーブル、ビュー、インデック
スで構成され、この 3 つの要素による基本構造をメタデータと呼びます。
重要
この章で説明する文は、DSQL(動的 SQL)アプリケーションでも使用できます。なお、DSQL
アプリケーションでは、このような文を実行時にユーザーが記述する場合、先頭に EXEC SQL
を記述する必要はありません。
メタデータの作成、修正、削除には、InterBase の対話型 SQL ツールである isql を使用する
のが一般的です。ただし、場合によっては、SQL アプリケーションにデータ定義文を記述
しなければならないこともあり、また、この方法が適していることもあります。SQL、およ
び DSQL アプリケーションで、次のようなデータ定義文を利用できます。
表 5.1
埋め込みアプリケーションで使用できるデータ定義文
CREATE 文
ALTER 文
DROP 文
CREATE DATABASE
ALTER DATABASE
—
CREATE DOMAIN
ALTER DOMAIN
DROP DOMAIN
CREATE GENERATOR
SET GENERATOR
—
CREATE INDEX
ALTER INDEX
DROP INDEX
CREATE SHADOW
ALTER SHADOW
DROP SHADOW
CREATE TABLE
ALTER TABLE
DROP TABLE
CREATE VIEW
—
DROP VIEW
DECLARE EXTERNAL
—
DROP EXTERNAL
DECLARE FILTER
—
DROP FILTER
第 5 章 データ定義文
5-1
メタデータの作成
DSQL では、上記の他に、ストアドプロシージャ、トリガー、例外の作成、変更、削除も行
うことができます。また、DSQL は、ユーザーが実行時にデータ定義文を入力できるという
点で、データ定義機能に関してはたいへん優れています。たとえば、isql はデータ定義のた
めのツールですが、この isql も DSQL アプリケーションの 1 つです。isql を使用したストア
ドプロシージャ、トリガー、および例外の定義の詳細は、
『データ定義ガイド』を参照して
ください。DSQL プログラミングの詳細は、第 13 章「動的 SQL」を参照してください。
重要
アプリケーションで、データ操作文のほか、データ定義文を使った場合は、gpre -m スイッ
チを使って前処理を行わなければなりません。したがって、このようなアプリケーションで
は、事前に SET TRANSACTION を使って明示的にトランザクションを起動しておく必要が
あります。
メタデータの作成
SQL のデータ定義文を使用することで、アプリケーション上でデータベースやテーブルの
作成、修正を行うことができます。ただし、データベースなどの作成や修正には isql を使用
するのが一般的で、こういったデータ定義文は、通常、ユーザーが 1 回だけ使って破棄す
るようなアプリケーションで使用します。アプリケーションは、もちろん保存しておいて
もかまいません。保存しておくと、将来データベース開発者がアプリケーションを修正す
る際、プログラムコードを参考にしてデータベースの構造をチェックすることができます。
実際、データ定義文を修正するだけであれば、既存のコードをコピーして、必要に応じて
手直した方が、最初から作成するよりも簡単です。
CREATE 文は、新規のデータベースやドメイン、テーブル、ビュー、インデックスの作成
に使用します。CREATE 文を記述したときは、その後に必ず COMMIT 文を記述しなければ
なりません。これで、後続の各 CREATE 文で、定義済みの関連メタデータを使用できるよ
うになります。たとえば、ドメインの定義では、コミットすることにより、そのドメインが
後続のテーブル定義で参照されるようになります。
メタデータ名
名前の長さ
テーブル、列、ドメインの名前などのメタデータ名には、最長 68 バイト(67 バイトと NULL
終端)を使用できます。旧バージョンの InterBase は、32 バイト以下のメタデータ名しかサ
ポートしません。このため、旧バージョンのクライアントは、32 バイトより長い名前を持
つデータベースオブジェクトにアクセスできません。
クライアントが長いメタデータ名にアクセスできるようにするには、XSQLDA 構造体の
version フィールドを SQLDA_CURRENT_VERSION に設定します。これは ibase.h で定義さ
れます。このバージョンは、長い名前を解釈するように設定されています。
区切り付き識別子
InterBase ダイアレクト 1 では、オブジェクト名の大文字と小文字が区別されません。また、
キーワード、空白、または非 ASCII 文字を含めることはできません。
5-2 埋 め 込 み S Q L ガ イ ド
メタデータの作成
ダイアレクト 3 では、二重引用符で囲まれたオブジェクト名は区切り付き識別子です。区切
り付き識別子は、大文字と小文字が区別され、キーワード、スペース、非 ASCII 文字を含
むことができます。次に例を示します。
SELECT “CodAR” FROM MyTable
これは、次の文とは異なります。
SELECT “CODAR” FROM MyTable
この動作は、区切り付き識別子に関する ANSI SQL のセマンティクスにしたがっています。
データベースの作成
CREATE DATABASE 文は、新しいデータベースを構築し、それに関連するシステムテーブ
ルを作成します。これらはデータベースの内部構造を示すテーブルです。ユーザーが作成
したテーブルと同様に、これらのテーブルの多くに含まれるデータを SQL プログラムで選
択できます。
CREATE DATABASE の構文の最も基本的な形式は次のとおりです。
EXEC SQL
CREATE DATABASE '<filespec>';
CREATE DATABASE は、他の CREATE 文より前に記述しなければなりません。パラメータ
は 1 つで、作成するデータベース名を指定します。たとえば、次は、countries.ib という名前
のデータベースを作成する文例です。
EXEC SQL
CREATE DATABASE 'countries.ib';
メモ
CREATE DATABASE では、ホスト名やノード名、ディレクトリパスなどのフルファイル名
を指定することもでき、この場合、その場所にデータベースが作成されることになります。
なお、ファイル仕様はオペレーティングシステムによって異なります。詳細は、オペレー
ティングシステムのマニュアルを参照してください。
重要
InterBase では、リモートデータベースにアクセスできるため、データベースをリモートマ
シンに作成することもできます。ただし、データベースの格納場所は変更できないので、
データベースを常駐させておくマシンに作成しなければなりません。
オプションパラメータ
CREATE DATABASE にはオプションでパラメータを付加することができます。たとえば、
クライアントのアプリケーションから InterBase サーバーに接続してデータベースを作成
する場合で、その接続にユーザー名とパスワードという条件を設ける必要があるとします。
このような場合、パラメータとして USER と PASSWORD が用意されています。このほか、
パラメータを使ってデータベースのページサイズ、マルチファイルデータベースの数とサ
イズ、データベースのデフォルトのキャラクタセットなどの設定を行うこともできます。
CREATE DATABEASE のパラメータの詳細は、
『データ定義ガイド』を参照してください。
CREATE DATABASE の構文の詳細は、
『言語リファレンス』を参照してください。
第 5 章 データ定義文
5-3
メタデータの作成
重要
データベースを作成するアプリケーションは gpre -m スイッチを使って前処理しておかな
ければなりません。加えて、gpre -m スイッチを使ってテーブルを最低 1 つ作成しておく必
要があります。事前にテーブルを作成せずにデータベースを作成した場合、別のプログラム
はそのデータベースを正常に開けません。データ定義とデータ操作の両方を処理するアプ
リケーションでは、必ず DECLARE TABLE を使ってテーブルを宣言してからテーブルの作
成と母集団の入力を行ってください。テーブルの作成の詳細は、5-5 ページの「テーブル
の作成」を参照してください。
デフォルトキャラクタセットの指定
CREATE DATABASE では、パラメータを使ってデータベースのデフォルトキャラクタセッ
トを指定することができます。ここでキャラクタセットを指定しておいた場合、CHAR、
VARCHAR、テキスト BLOB のデータが、サーバー側で自動的にそのキャラクタセットに
コード変換され格納されます。ただし、明示的にキャラクタセットの指定があったときは、
そのキャラクタセットが使用されます。このデフォルトキャラクタセットは、CREATE
DATABASE でデータベースを作成する際は必ず指定しておきます。
デフォルトキャラクタセットの指定は、CREATE DATABSE 文の DEFAULT CHARACTER
SET 句を使用します。たとえば、次の文では、ISO8859_1 キャラクタセットを使用するデー
タベースが作成されます。
EXEC SQL
CREATE DATABASE 'europe.ib' DEFAULT CHARACTER SET ISO8859_1;
キャラクタセットを指定しなかった場合、キャラクタセットはデフォルトの NONE に設定
されます。デフォルトが NONE であるということは、列で使用されるキャラクタセットが
存在しないことを意味します。したがって、データは、入力の時点で使用しているキャラ
クタセットを使って列に格納され、また取り出されることになります。NONE が設定され
ている列には、後で任意のキャラクタセットをロードすることができますが、異なるキャ
ラクタセットが設定されている列にそのデータを後で移動することはできません。この場
合には、移動元のキャラクタセットと移動先のキャラクタセットとの間でコード変換は行
われず、このため、移動中にエラーが発生することがあります。
DEFAULT CAHRACTER SET 句、および InterBase がサポートするキャラクタセットの詳細
は、『データ定義ガイド』を参照してください。
ドメインの作成
CREATE DOMAIN を使用して、ドメイン(列で使用されるデータ型、名前付き)を作成す
ることができます。作成したドメインは、データベース全体で有効で、後続の CREATE
TABLE 文で使用することができます。特に、データベースのテーブル数が多く、各テーブ
ルに同じ定義(データ型)の列がある場合に、CREATE DOMAIN を使ってドメインを作成
しておくと便利です。たとえば、従業員管理データベースでは、通常、複数のテーブルに従
業員の姓と名を記録するテーブルが配置されます。このような場合に、各テーブルの作成
にドメインを使用します。
CREATE DOMAIN の基本構文は、次のようになります。
EXEC SQL
CREATE DOMAIN name AS <datatype>;
5-4 埋 め 込 み S Q L ガ イ ド
メタデータの作成
たとえば、FIRSTNAME と LASTNAME という名前で 2 つのドメインを作成する場合、記述
は次のようになります。
EXEC SQL
CREATE DOMAIN FIRSTNAME AS VARCHAR(15);
EXEC SQL
CREATE DOMAIN LASTNAME AS VARCHAR(20);
EXEC SQL
COMMIT;
ドメインの作成とコミットが終了すれば、そのドメインは後続の CREATE TABLE 文の列の
定義で利用できます。たとえば、次の CREATE TABLE 文は、EMPLOYEE というテーブルを
作成する場合で、ここでは、列の定義でデータ型を指定するかわりに、FIRSTNAME と
LASTNAME という 2 つのドメインを使用しています。
EXEC SQL
CREATE TABLE EMPLOYEE
(
. . .
FIRST_NAME FIRSTNAME NOT NULL,
LAST_NAME LASTNAME NOT NULL;
. . .
);
また、ドメインでは、デフォルト値、NOT NULL 属性、CHECK 制約(挿入や更新で値が
一定範囲に限定されます)
、キャラクタセット、照合順序を指定することもできます。
ドメインの作成と、テーブルの作成中にドメインを使用する方法の詳細は、
『データ定義ガ
イド』を参照してください。CREATE DOMAIN の構文の詳細は、
『言語リファレンス』を
参照してください。
テーブルの作成
テーブルの新規作成には、CREATE TABLE 文を使用します。文では、テーブルの名前と列
を指定します。オプションで整合性制約を指定することもできます。列にはそれぞれ、キャ
ラクタセットや照合順序を付加することができます。CREATE TABLE が実行されると、そ
のテーブルに対して自動的にデフォルトの SQL セキュリティスキーマが設定されます。ま
た、テーブルの作成者がオーナーとなります。オーナーにはテーブルに関連する特権がすべ
て割り当てられます。この特権には、他のユーザーに対して特権を認可する権利も含まれ
ます。
テーブルを作成するには、事前にデータベースを作成しておかなければなりません。
CREATE TABLE の基本構文は、次のとおりです。
EXEC SQL
CREATE TABLE name (<col_def> | <table_constraint>
[, <col_def> | <table_constraint> ...]);
ここで、col_def は次の構文を使って列を定義します。
<col> {<datatype> | COMPUTED [BY] (<expr>) | domain}
[DEFAULT {literal | NULL | USER}]
第 5 章 データ定義文
5-5
メタデータの作成
[NOT NULL]
[<col_constraint>]
[COLLATE collation]
col は列の名前で、同じテーブル定義内で一意でなければなりません。
datatype はデータ型で、その列に入力される値のデータ型を指定します。COMPUTED BY
は、実行時のアクセスの際に、なんらかの式によってその列の値が与えられる場合に使用
します。
col_constraint は、オプションの整合性制約で、その列全体に対して適用されます。
table_constraint は、同じくオプションの整合性制約で、テーブル全体に対して働きます。
これらの整合性制約は、なんらかの条件に合致するデータだけをテーブルに入力する場合
に利用できます。整合性制約では、このほか、テーブルや列にデータが重複して入力され
ないようにしたり、データベース中の他のテーブルとの参照の整合性の設定などが可能で
す。
列定義には、デフォルト値を含めることができます。例:
stringfld VARCHAR(10) DEFAULT ‘abc’
integerfld INTEGER DEFAULT 1
numfld NUMERIC(15,4) DEFAULT 1.5
datefld1 DATE DEFAULT ‘2/01/2001’
datefld2 DATE DEFAULT ‘TODAY’
userfld VARCHAR(12) DEFAULT USER
最後の 2 行では、InterBase の特別な機能を使用しています。‘TODAY’ は、その時点の日付
になります。USER は、その列の挿入を行っているユーザーです。
次の CREATE DATABASE 文と CREATE TABLE 文の例では、employee.ib というデータベース
を作成するとともに、EMPLOYEE_PROJECT という名前のテーブルを作成しています。列
は、EMP_NO、PROJ_ID、DUTIES です。
EXEC SQL
CREATE DATABASE 'employee.ib';
EXEC SQL
CREATE TABLE EMPLOYEE_PROJECT
(
EMP_NO SMALLINT NOT NULL,
PROJ_ID CHAR(5) NOT NULL,
DUTIES Blob SUB_TYPE 1 SEGMENT SIZE 240
);
EXEC SQL
COMMIT;
複数のテーブルを作成することができますが、名前の重複するものは作成できません。
SQL データ型と整合性制約の詳細は、
『データ定義ガイド』を参照してください。CREATE
『言語リファレンス』を参照してください。テーブル特権の変更また
TABLE 構文の詳細は、
は割り当ての詳細は、『データ定義ガイド』を参照してください。
5-6 埋 め 込 み S Q L ガ イ ド
メタデータの作成
計算列の作成
計算列とは、実行時、その列にアクセスが行われると同時に値が計算されるような列を言
います。値は、正規の SQL の式により与えられます。この場合、式は、配列ではない 1 つ
の値を出力するものでなければなりません。計算列は、データベースに物理的に格納されて
いるデータに対応していないという意味で「仮想的」であると言えます。計算列の値は常に
SELECT クエリーが行われるときに生成されます。基になっている値が変更された場合は、
それに対応して動的に生成されます。
計算列を作成する場合、CREATE TABLE 文で次の列宣言構文を記述します。
col COMPUTED [BY] (<expr>)
expr は式です。式では、テーブルに定義されている列の値を使用できます。たとえば、次
の文は、FIRST_NAME と LAST_NAME という 2 つの列の値を連結して、FULL_NAME とい
う計算列に入力する例です。
EXEC SQL
CREATE TABLE EMPLOYEE
(
. . .
FIRST_NAME VARCHAR(10) NOT NULL,
LAST_NAME VARCHAR(15) NOT NULL,
. . .
FULL_NAME COMPUTED BY (LAST_NAME || ', ' || FIRST_NAME)
);
COMPUTED BY の詳細は、
『データ定義ガイド』を参照してください。
テーブルの宣言と作成の関係
CREATE TABLE 文を使ってテーブルを作成する場合、それに先だって、DECLARE TABLE
でテーブルの宣言を行っておく必要があります。この宣言により、テーブルの構造が
InterBase のプリプロセッサである gpre に報告されることになります。つまり、gpre での前
処理中に DECLARE TABLE 文が見つかると、宣言されているテーブルの内容がいったん記
憶されます。CREATE TABLE 文が見つかった場合、その CREATE 文での列定義と、記憶さ
れている DECLARE 文の列定義が一致しているかどうかの検査が行われます。この検査で
列定義が一致しないときは、gpre によりエラーが報告され、前処理が中止されます。この
場合、プログラムを修正しなければなりません。
DECLARE TABLE 文は CREATE TABLE 文の前に記述しなければなりません。
たとえば、次の例では、DECLARE TABLE で EMPLOYEE_PROJECT というテーブルを宣言
した後に、CREATE TABLE でテーブルを作成しています。
EXEC SQL
DECLARE EMPLOYEE_PROJECT TABLE
(
EMP_NO SMALLINT,
PROJ_ID CHAR(5),
DUTIES Blob(240, 1)
);
EXEC SQL
第 5 章 データ定義文
5-7
メタデータの作成
CREATE TABLE EMPLOYEE_PROJECT
(
EMP_NO SMALLINT,
PROJ_ID CHAR(5),
DUTIES Blob(240, 1)
);
EXEC SQL
COMMIT;
DECLARE TABLE の詳細は、
『言語リファレンス』を参照してください。
ビューの作成
ビューとは、データベース中の 1 つ以上のテーブルの一部をもとに作成された仮想テーブ
ルです。ビューの使用には、次のような利点があります。
• テーブルに公開したくないデータがある場合、そのデータを除外したビューを作成するこ
とで、このようなデータに対するユーザーのアクセスを制限できます。
• 複数のテーブルがある場合、各テーブルから必要なデータだけを選択し、再編成したテー
ブル(ビュー)を作成できます。このビューのデータは、ユーザーからの読み取りが可能
です。
テーブルのデータはデータベースに格納されますが、ビューの場合、これとは異なり、作成
の際にその定義だけがデータベースに格納されます。プログラムでビューが必要になった
場合は、InterBase によりビューの定義が読み取られるとともに、テーブルと同じように瞬
時に出力が生成されます。
ビューは、次の CREATE VIEW 構文を使って作成できます。
EXEC SQL
CREATE VIEW name [(view_col [, view_col ...)]AS
<select> [WITH CHECK OPTION];
上記の構文中、name はビュー名です。この名前は、そのデータベースに同じものがあって
はなりません。
ビューの列に独自の名前(view_col)、つまり作成元のテーブルの列とは違う名前を付けた
いときは、その名前を name の右にカンマで区切って順に記述します。先頭と末尾はかっこ
で囲みます。これで、その名前が、CREATE VIEW の SELECT 文の右に指定した作成元の
テーブルの列の順番どおりに、ビューの列にそれぞれ割り当てられることになります。な
お、独自の名前を記述しなかったときは、テーブルの列名がビューでもそのまま使用され
ます。
ビューに独自の名前を付けた場合、その名前はテーブルの列名とは独立して扱われます。こ
のため、作成元のテーブルの構成が変更されても、ビューの構成は変わりません。
メモ
ビューの列名は、CREATE VIEW の SELECT 文の右に指定した列名と同じ数だけ記述する
か、または、何も記述しないかのどちらかでなければなりません。
5-8 埋 め 込 み S Q L ガ イ ド
メタデータの作成
select 句の部分には、通常の SELECT 文を記述します。つまり、ビューに取り込む列名の他
に、ビューに取り込む行の選択条件を指定できます。ただし、CREATE VIEW の SELECT で
は、ORDER BY 句は使用できません。また、DSQL では、ORDER BY 句の他に、UNION 句
も使用できません。
WITH CHECK OPTION はオプションで、このオプションを使用することにより、ビューに
対するデータの挿入、更新、削除が制限されます。
ビューには、読み取り専用のビューと更新可能なビューの 2 種類があります。読み取り専
用のビューを作成する場合、ビューの作成者がビューの作成元の 1 つ以上のテーブルに対
し SELECT 特権を所有していることが必要です。一方、更新可能なビューを作成する場合、
ビューの作成元の 1 つ以上のテーブルに対し ALL 特権を持っていることが条件となりま
す。SQL 特権の詳細は、『データ定義ガイド』に記載されているセキュリティについての章
を参照してください。
読み取り専用のビューの作成
ビューは、複数のテーブルに基づいて作成することができます。また、既存の複数のビュー
を基礎にしてビューを作成することもできます。このように、複数のテーブルまたは他の
ビューをもとにして作成したビューは、自動的に読み取り専用のビューとなります。した
がって、更新は不可能です。たとえば、次は、読み取り専用のビューを作成する文の例で
す。作成するビュー名は PHONE_LIST で、EMPLOYEE と DEPARTMENT の 2 つが作成元の
テーブルです。したがって、このビューは読み取り専用となります。
EXEC SQL
CREATE VIEW PHONE_LIST AS
SELECT EMP_NO, FIRST_NAME, LAST_NAME, LOCATION, PHONE_NO
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.DEPT_NO = DEPARTMENT.DEPT_NO;
EXEC SQL
COMMIT;
重要
作成したビューは、そのままの状態では作成者しかアクセスすることができません。一般の
ユーザーは、GRANT で許可を与えられた後で読み取りが可能になります。GRANT の詳細
は、データ定義ガイドに記載されているセキュリティについての章を参照してください。
更新可能なビューの作成
更新可能なビューとは、更新の特権が与えられているユーザーが、ビューの作成元のテー
ブルのデータに対して、挿入、更新、削除といった処理が可能なビューです。なお、更新可
能なビューを作成する場合、次のような条件に適合していなければなりません。
• 作成元のテーブルが 1 つであること。既存のビューが作成元でもかまいませんが、この場
合、そのビューが 1 つで更新可能であることが必要です。
• ビューの SELECT 文で指定されているテーブルは 1 つでなければなりません。
• 作成元のテーブルに計算列がある場合、その列がビューに取り込まれていてはなりません。
• ビューの SELECT 文には、次の句などが記述されていてはなりません。
• DISTINCT が記述されている WHERE 句
• HAVING 句
第 5 章 データ定義文
5-9
メタデータの作成
• 関数
• ネストされたクエリー
• ストアドプロシージャ
次は、HIGH_CITIES という名前の更新可能ビューを作成する場合の記述です。この例では、
WHERE で指定されている条件により、CITIES というテーブル中の ALTITUDE が 2640
フィート以上の市(行)がすべてビューに取り込まれます。
EXEC SQL
CREATE VIEW HIGH_CITIES AS
SELECT CITY, COUNTRY_NAME, ALTITUDE FROM CITIES
WHERE ALTITUDE >= 2640;
EXEC SQL
COMMIT;
上のビューの場合、このビューに対して INSERT 特権や UPDATE 特権を所有するユーザー
であれば、作成元のテーブルである CITIES に行を挿入したり、新規の行を追加することが
できます。このほか、ビュー HIGH_CITIES に取り込まれていない行に対しても、挿入や更
新が可能です。たとえば、次は、INSERT を使って CITIES テーブルに、市名が Santa Cruz、
国名が United States、高度が 23 フィートというレコード(行)を追加する場合の記述です。
EXEC SQL
INSERT INTO HIGH_CITIES (CITY, COUNTRY_NAME, ALTITUDE)
VALUES ('Santa Cruz', 'United States', '23');
ビューに取り入れた行以外は、ユーザーに挿入や更新を制限する場合は、WITH CHECK
OPTION を 付 加 し ま す。たとえば、次の文は、ビュー HIGH_CITIES を WITH CHECK
OPTION を使って作成する場合の記述です。これで、INSERT 特権や UPDATE 特権を所有す
るユーザーであっても、市の高度が 2640 フィート以上という条件に該当しない行は入力で
きなくなります。
EXEC SQL
CREATE VIEW HIGH_CITIES AS
SELECT CITY, COUNTRY_NAME, ALTITUDE FROM CITIES
WHERE ALTITUDE > 2640 WITH CHECK OPTION;
インデックスの作成
SQL には CREATE INDEX が用意されており、この文を使ってユーザー定義のインデックス
を作成できます。インデックスは、テーブル中の列をもとにして作成される参照テーブル
で、CREATE INDEX では列を指定して作成できます。列に対してインデックスを作成して
おくと、クエリーの際にデータの検索が高速化されます。CREATE INDEX の構文は次のと
おりです。
EXEC SQL
CREATE [UNIQUE] [ASC[ENDING] | DESC[ENDING]] INDEX <index> ON
table (col [, col ...]);
たとえば、次の文では、EMPLOYEE テーブルの LAST_NAME と FIRST_NAME という 2 つ
の列に対して、NAMEX という名前のインデックスを作成しています。
5-10 埋 め 込 み S Q L ガ イ ド
メタデータの作成
EXEC SQL
CREATE INDEX NAMEX ON EMPLOYEE (LAST_NAME, FIRST_NAME);
メモ
InterBase では、テーブルの定義の際、UNIQUE や PRIMARY KEY などの制約を指定してお
くと、自動的にシステムレベルのインデックスが生成されます。UNIQUE と PRIMARY KEY
の詳細は、『データ定義ガイド』を参照してください。
CREATE INDEX 構文の詳細は、
『言語リファレンス』を参照してください。
インデックスによる重複データの入力の排除
場合によっては、列に同じデータを重複して入力してしまうことがありますが、これは、
CREATE INDEX に UNIQUE キーワードを付加することにより防止できます。たとえば、次
の文は、PROJECT テーブルに、PRODTYPEX という名前のユニークインデックスを作成し
ている例です。
EXEC SQL
CREATE UNIQUE INDEX PRODTYPEX ON PROJECT (PRODUCT, PROJ_NAME);
重要
ユニークインデックスの作成後は、ユーザーは、その列にすでに記録されているものと重
複するデータを入力することができなくなります。また、更新後のデータと同じデータが
すでに記録されている場合も同じです。なお、上記の PRODTYPEX のように、複数の列に
対してユニークインデックスが定義されている場合、いずれか 1 つの列には重複してデー
タを入力できますが、インデックスが設定されている列全部にデータを入力したとき、そ
の組み合わせと同じものが他の行にあった場合、入力は拒否されます。
インデックスのソート順序の指定
SQL では、デフォルトではインデックスは昇順で作成されます。昇順ではなく、降順でイン
デックスを作成するときは、DESCENDING キーワードを使ってインデックスを定義しま
す。 た と え ば、SALARY_HISTORY テーブルの CHANGE_DATE という列をもとに
CHANGEX というインデックスを作成する場合、次のようになります。
EXEC SQL
CREATE DESCENDING INDEX CHANGEX ON SALARY_HISTORY (CHANGE_DATE);
メモ
降順のインデックスが設定されている列からデータを取り出すときは、SELECT 文で ORDER
BY を使って降順を指定します。
ジェネレータの作成
ジェネレータとは、単調に増減する数値を生成するメカニズムを指します。このジェネレー
タで生成される数値は、アプリケーションの SQL 文またはトリガーを使って項目に挿入で
きます。ジェネレータは、通常、列に一意な値を挿入する場合に作成しておきます。ジェネ
レータにより数値が入力された列は、主キー(ソートでの基本列)として利用できます。
アプリケーションで使用するジェネレータは、CREATE GENERATOR 構文を使って作成で
きます。構文は次のとおりです。
EXEC SQL
CREATE GENERATOR name;
第 5 章 データ定義文
5-11
メタデータの削除
たとえば、従業員にそれぞれ一意な番号を割り当てたい場合、次の文でジェネレータを作
成しておきます。名前は、内容がわかりやすいように EMP_NO_GEN としておきます。
EXEC SQL
CREATE GENERATOR EMP_NO_GEN;
EXEC SQL
COMMIT;
ジェネレータによって生成される数値の初期値は、SET GENERATOR で指定することがで
きます。また、数値は、割り当て文で InterBase ライブラリの GEN_ID() 関数を使って項目
に挿入できます。GEN_ID()、CREATE GENERATOR、および SET GENERATOR の詳細は、
『データ定義ガイド』を参照してください。
メタデータの削除
作成したメタデータ(テーブル、ビュー、インデックス)は、次の SQL 文を使って削除で
きます。
• DROP TABLE:データベースからテーブルを削除するために使用します。
• DROP VIEW:データベースからビューの定義を削除するために使用します。
• DROP INDEX:インデックスを削除するために使用します。
• ALTER TABLE:テーブルの列を削除するために使用します。
ALTER TABLE を含んだ列の削除の詳細は、5-14 ページの「テーブルの修正」を参照して
ください。
インデックスの削除
インデックスは、DROP INDEX を使って削除できます。インデックスを削除できるのは、作
成者、SYSDBA またはルート特権を持つユーザーに限られます。また、なんらかの処理でイ
ンデックスが使用されている最中に削除が行われたときは、インデックスの使用が終了す
るのを待って削除が行われます。DROP INDEX の構文は次のとおりです。
EXEC SQL
DROP INDEX name;
上記の構文中、name は削除するインデックス名です。たとえば、NEEDX という名前のイン
デックスを削除する場合、次のようになります。
EXEC SQL
DROP INDEX NEEDX;
EXEC SQL
COMMIT;
なお、インデックスに UNIQUE、PRIMARY KEY、FOREIGN KEY などの整合性制約が設定
されている場合、そのままでは削除できません。このようなインデックスを削除するには、
まず、その制約を削除します。または、制約が設定されている列またはテーブルを削除し
ます。
DROP INDEX と整合性制約の削除の詳細は、
『データ定義ガイド』を参照してください。
5-12 埋 め 込 み S Q L ガ イ ド
メタデータの削除
ビューの削除
ビューは、DROP VIEW を使って削除できます。ビューを削除できるのは、作成者、SYSDBA
またはルート特権を持つユーザーに限られます。また、なんらかの処理でビューが使用され
ている最中に削除が行われたときは、ビューの使用が終了するのを待って削除が行われま
す。DROP VIEW の構文は次のとおりです。
EXEC SQL
DROP VIEW name;
EMPLOYEE_ SALARY という名前のビューを削除する場合、次のようになります。
EXEC SQL
DROP VIEW EMPLOYEE_SALARY;
EXEC SQL
COMMIT;
なお、削除するビューが別のビューで使用されている場合は、削除はできません。トリガー
や計算列で使用されている場合も同じです。このようなビューは、次の手順で削除できます。
1
2
そのビューを使用しているビュー、トリガー、計算列を削除します。
この後、ビューを削除します。
DROP VIEW の詳細は、
『データ定義ガイド』を参照してください。
テーブルの削除
データベースのテーブルは、DROP TABLE を使って削除できます。テーブルを削除できる
のは、作成者、SYSDBA またはルート特権を持つユーザーに限られます。なんらかの処理で
テーブルが使用されている最中に削除が行われたときは、テーブルの使用が終了するのを
待って削除が行われます。DROP TABLE の構文は次のとおりです。
EXEC SQL
DROP TABLE name;
ここで、name は削除するテーブル名です。たとえば、EMPLOYEE という名前のテーブルを
削除する場合、次のようになります。
EXEC SQL
DROP TABLE EMPLOYEE;
EXEC SQL
COMMIT;
なお、削除するテーブルがビューで使用されている場合、削除はできません。トリガーや
計算列で使用されている場合も同じです。また、テーブルに整合性制約である UNIQUE や
PRIMARY KEY が設定されており、このような制約が他のテーブルの FOREIGN KEY によっ
て参照されている場合も削除できません。このような場合、まず、他のテーブルの FOREIGN
KEY を削除した後、テーブルを削除します。
メモ
テーブル中の列は、全部一括して削除する必要はなく、任意の列を指定して削除できます。
詳細は、5-15 ページの「既存の列の削除」を参照してください。
DROP TABLE の詳細は、
『データ定義ガイド』を参照してください。
第 5 章 データ定義文
5-13
メタデータの変更
メタデータの変更
データ定義(データの入力を可能にするための準備)では、通常はテーブルに関する変更
作業が最も多くなります。中でも、テーブルに新規の列を追加したり、不要になった列を
削除する作業が中心になります。SQL では ALTER TABLE が用意されており、この文を使用
して、テーブルへの新規の列の追加や既存の列の削除が可能です。ALTER TABLE では、1
つの文で列の追加と削除を同時に行うこともできます。ALTER TABLE などでメタデータを
直接操作すると、メタデータのバージョンがインクリメントされます。データベースのバッ
クアップと復元を行うまでの間に、最大で 255 回までテーブル(およびそのトリガー)を
変更することができます。
ビューとインデックスを変更する場合は、次の 2 段階の操作が必要です。
1
2
まず、既存のビューやインデックスを削除します。
その後、新規のビューやインデックスを作成します。
場合によっては、既存のメタデータ(テーブル、ビュー、インデックス)を削除できない
ことがあります。このような場合、同じ名前のメタデータは作成できません。メタデータの
削除に失敗する状況としては、次の 3 つがあります。
• メタデータの作成者以外のユーザーが、メタデータを削除しようとした場合
• メタデータに SQL の整合性制約が設定されており、その制約が別のメタデータによって参
照されている場合
• メタデータが、別のビュー、トリガー、計算列で使用されている場合
メタデータの削除の詳細は、5-12 ページの「メタデータの削除」を参照してください。
テーブルの修正
ALTER TABLE では、既存のテーブルに対して次のような修正作業が可能です。
• 列の定義の追加
• テーブルの制約の追加
• 列の定義の削除
• テーブルの制約の削除
• 列に設定されている定義の変更(既存の定義の削除後に別の定義を追加)
• テーブルに設定されている制約の変更(既存の定義の削除後に別の定義を追加)
• 列の名前とデータ型の変更
ALTER TABLE の基本構文は次のとおりです。
EXEC SQL
ALTER TABLE name {ADD colname <datatype> [NOT NULL]
| ALTER [COLUMN] simple_column_name alter_rel_field
| DROP colname | ADD CONSTRAINT constraintname tableconstraint
| DROP CONSTRAINT constraintname};
メモ
テーブルの制約の追加、削除、修正の詳細は、『データ定義ガイド』を参照してください。
5-14 埋 め 込 み S Q L ガ イ ド
メタデータの変更
ALTER TABLE の構文の詳細は、
『言語リファレンス』を参照してください。
テーブルへの新規の列の追加
ALTER TABLE を使用して、既存のテーブルに対して新規の列を追加することができます。
ただし、列の追加が可能なのは、そのテーブルの作成者に限られます。新規の列を追加する
場合、ALTER TABLE の構文は次のようになります。
EXEC SQL
ALTER TABLE name ADD colname <datatype> colconstraint
[, ADD colname datatype colconstraint ...];
たとえば、EMPLOYEE というテーブルに EMP_NO という列を追加する場合、次のように
なります。
EXEC SQL
ALTER TABLE EMPLOYEE ADD EMP_NO EMPNO NOT NULL;
EXEC SQL
COMMIT;
上記の例では、ドメインである EMPNO を使って列の定義を行っています。ドメインの詳
細は、『データ定義ガイド』を参照してください。
上記の例では追加する列は 1 つですが、複数の列を一度に追加することもできます。この場
合、追加する列名をカンマで区切ります。たとえば、次の文は、EMPLOYEE テーブルに、
EMP_NO と FULL_NAME という 2 つの列を追加する例です。このうち、FULL_NAME は計
算列で、他の列の値をもとにした計算によって値が得られます。
EXEC SQL
ALTER TABLE EMPLOYEE
ADD EMP_NO EMPNO NOT NULL,
ADD FULL_NAME COMPUTED BY (LAST_NAME || ', ' || FIRST_NAME);
EXEC SQL
COMMIT;
上記の例では、FULL_NAME 列の値は、定義済みの LAST_NAME と FIRST_NAME という
2 つの列によって算出されることになります。計算列の作成の詳細は、
『データ定義ガイド』
を参照してください。
テーブルに新規の列を追加する場合、整合性制約とともに定義することができます。整合性
制約を持った列をテーブルへ追加する方法の詳細は、
『データ定義ガイド』を参照してくだ
さい。
既存の列の削除
ALTER TABLE では、既存の列の削除を行うこともできます。なお、列を削除した場合、そ
の列のデータも削除されます。列を削除できるのは、テーブルの作成者、SYSDBA または
ルート特権を持つユーザーに限られます。また、なんらかの処理でテーブルが使用されてい
る最中に削除が行われたときは、テーブルの使用が終了するのを待って削除が行われます。
ALTER TABLE で列を削除する場合の構文は次のとおりです。
EXEC SQL
ALTER TABLE name DROP colname [, colname ...];
たとえば、次の文では、EMP_NO 列が EMPLOYEE テーブルから削除されます。
第 5 章 データ定義文
5-15
メタデータの変更
EXEC SQL
ALTER TABLE EMPLOYEE DROP EMP_NO;
EXEC SQL
COMMIT;
ALTER TABLE で は、ま た、複数の列を同時に削除することもできます。 たとえば、
EMPLOYEE テーブルから、EMP_NO と FULL_NAME という 2 つの列を削除する場合、次
の文のようになります。
EXEC SQL
ALTER TABLE EMPLOYEE
DROP EMP_NO,
DROP FULL_NAME;
EXEC SQL
COMMIT;
なお、列に UNIQUE、PRIMARY KEY、FOREIGN KEY などの整合性制約が設定されている
場合、そのままでは削除できません。この場合、その制約を削除した後、列を削除します。
また、列が、他の列との関連で CHECK 制約により使用された場合も削除はできません。こ
の場合、先に CHECK 制約を削除してから列を削除します。
整合性制約の詳細は、
『データ定義ガイド』を参照してください。
列の変更
ALTER TABLE では、データ型やサイズなど、列の定義の内容を変更することもきます。す
でに列に格納されているデータは、列の内容を変更した時点で失われます。
したがって、格納されているデータが必要な場合、次の 5 段階の手順にしたがって列の定
義の内容を変更しなければなりません。
1
テーブルに一時的な列を追加します。この列に、変更する列(古い列)の現在のメタ
データを一時的に保存することになります。
2
3
4
5
古い列のデータを、新たに作成した一時的な列にコピーします。
古い列の定義を変更します。
一時的な列から古い列へデータをコピーします。
一時的な列を削除します。
例
たとえば、EMPLOYEE テーブルに OFFICE_NO という列があり、その列に定義されている
データ型が CHAR(3) だったとします。この場合、データ型はこのままで、サイズを 1 文字
だけ増やすことにしたとします。この場合、サイズの変更は、次の 5 段階の手順にしたがっ
て進められます。
6
まず、変更プロセス中に OFFICE_NO のデータを保存する一時的な列を作成します。
EXEC SQL
ALTER TABLE EMPLOYEE ADD TEMP_NO CHAR(3);
EXEC SQL
COMMIT;
5-16 埋 め 込 み S Q L ガ イ ド
メタデータの変更
7
既存のデータを OFFICE_NO から TEMP_NO へ移し、保存します。
EXEC SQL
UPDATE EMPLOYEE
SET TEMP_NO = OFFICE_NO;
8
OFFICE_NO の列定義を変更し、データ型と新しいサイズを指定します。
EXEC SQL
ALTER TABLE EMPLOYEE ALTER OFFICE_NO TYPE CHAR(4);
EXEC SQL
COMMIT;
9
データを TEMP_NO から OFFICE_NO へ移します。
EXEC SQL
UPDATE EMPLOYEE
SET OFFICE_NO = TEMP_NO;
10 最後に、TEMP_NO 列を削除します。
EXEC SQL
ALTER TABLE DROP TEMP_NO;
EXEC SQL
COMMIT;
列の定義の削除の詳細は、5-15 ページの「既存の列の削除」を参照してください。
列の定義を追加する方法については、5-16 ページの「列の変更」を参照してください。
ALTER TABLE ALTER コマンドを使用すると、列の位置と名前を変更できます。
たとえば、次の文では、EMPLOYEE テーブルの EMP_NO 列が 3 番めの位置から 2 番めの
位置に移動されます。
ALTER TABLE EMPLOYEE ALTER EMP_NO POSITION 2;
また、次に示すように、EMP_NO 列の名前を EMP_NUM に変更することもできます。
ALTER TABLE EMPLOYEE ALTER EMP_NO TO EMP_NUM;
重要
項目の定義を変更した場合は、インデックスを再構築する必要があります。
ALTER TABLE の構文の詳細は、
『言語リファレンス』を参照してください。
ビューの修正
ビューを修正する場合、次の操作が必要になります。
1
2
まず、現在のビューを削除します。
その後、新規のビューを作成します。この場合、名前は削除したビューと同じものとし
ます。
たとえば、次のビューは、従業員の給料に関する情報を読み取るためのビューです。
EXEC SQL
CREATE VIEW EMPLOYEE_SALARY AS
SELECT EMP_NO, LAST_NAME, CURRENCY, SALARY
第 5 章 データ定義文
5-17
メタデータの変更
FROM EMPLOYEE, COUNTRY
WHERE EMPLOYEE.COUNTRY_CODE = COUNTRY.CODE;
このビューでは、従業員の姓しか表示されませんが、姓と名の両方を表示する必要がある
とします。この場合、まず現在のビューを削除します。
EXEC SQL
DROP EMPLOYEE_SALARY;
EXEC SQL
COMMIT;
削除が終わったら、次のようにして新規のビューを作成します。これで、従業員名が表示
されるようになります。
EXEC SQL
CREATE VIEW EMPLOYEE_SALARY AS
SELECT EMP_NO, FULL_NAME, CURRENCY, SALARY
FROM EMPLOYEE, COUNTRY
WHERE EMPLOYEE.COUNTRY_CODE = COUNTRY.CODE;
EXEC SQL
COMMIT;
インデックスの修正
インデックスを修正する場合、次の操作が必要になります。
1
2
3
ALTER INDEX を使用して、現在のインデックスを使用停止にします。
この後、現在のインデックスを削除します。
最後に、新規のインデックスを作成します。新規のインデックス名は、削除したイン
デックスと同じものにします。
インデックスの作成後、それまでとは異なる列にインデックスを設定したり、設定済みの
インデックスをはずす場合があります。また、UNIQUE を使って重複データの入力を防止
したり、逆に許可したり、さらに、ソート順を変更する場合もあります。インデックスの
修正は、通常、このような場合に行います。たとえば、次のように NAMEX という名前の
インデックスがあるとします。
EXEC SQL
CREATE INDEX NAMEX ON EMPLOYEE (LAST_NAME, FIRST_NAME);
その後、重複データの入力を防ぐ必要が出てきました。したがって、UNIQUE キーワード
を追加しなければなりません。この場合、まず、次のようにして現在のインデックスを使用
停止にし、それから削除します。
EXEC SQL
ALTER INDEX NAMEX INACTIVE;
EXEC SQL
DROP INDEX NAMEX;
EXEC SQL
COMMIT;
5-18 埋 め 込 み S Q L ガ イ ド
メタデータの変更
続いて、新規のインデックスを作成します。定義内容は以前と同じで、名前も同じく NANEX
とします。ただし、UNIQUE キーワードを追加します。
EXEC SQL
CREATE UNIQUE INDEX NAMEX ON EMPLOYEE (LAST_NAME, FIRST_NAME);
EXEC SQL
COMMIT
ALTER INDEX を直接使用すると、インデックスのソート順を変更したり、固有入力データ
または重複入力データを取り扱えるようになります。たとえば、NAMEX インデックスを変
更して重複入力データを取り扱えるようにする文には以下のものがあります。
EXEC SQL
ALTER INDEX NAMEX DUPLICATE;
重要
インデックスを直接変更する場合には注意が必要です。たとえば、インデックスの停止およ
び再作成を事前に完了せずに、重複入力データをサポートするインデックスを、固有入力
データが必要なインデックスに変更した場合は、インデックスのパフォーマンスが低下し
ます。
インデックスの削除の詳細は、5-12 ページの「インデックスの削除」を参照してください。
インデックスの作成の詳細は、5-10 ページの「インデックスの作成」を参照してください。
第 5 章 データ定義文
5-19
5-20 埋 め 込 み S Q L ガ イ ド
第
章
データ処理
第6章
埋め込みプログラムの SQL 文は、そのほとんどがデータの読み取りや修正、データベース
への新規データの追加といった処理にかかわるものです。この章では、InterBase で認識可
能なデータ型の紹介と併せて、SQL 式と、次に示す SQL 文を使ったデータの取り出し、修
正、追加、削除を行う方法について説明します。
SELECT 文:データベースに対してクエリーを実行し。つまり、データベースからの既存の
データの読み取り、取り出しを行うときに使用します。SELECT 文では、必要に応じて、次
の 4 種類の方法でデータを取り出すことができます。
• 1 つのテーブルの 1 行、または 1 行の中の任意のデータの取り出し。この取り出しを
単一行 SELECT と呼びます。
• 1 つのテーブルの複数行、または複数行の中の任意のデータの取り出し。この取り
出しには、DECLARE CURSOR 文の中で SELECT を使用します。
• 複数のテーブルに相互に関係している行がある場合、その行、または関係している
行の中の任意のデータの取り出し。この場合、取り出された行は、仮想テーブルま
たは結果テーブルに格納されます。この取り出しを結合(join)と呼びます。
• 複数のテーブルの全部の行、または全部の行の中の任意のデータの取り出し。この
場合、データは仮想テーブルに格納されます。この取り出しを合併(union)と呼び
ます。
• INSERT 文:テーブルへ新規の行を書き込みます。
• UPDATE 文:テーブルの既存の行を修正します。
• DELETE 文:テーブルの既存の行を削除します。
SELECT 文を使ってデータを取り出す方法については、6-18 ページの「SELECT による
データの取り出し」を参照してください。SELECT を使っての単一行の取り出しの詳細は、
6-35 ページの「1 行の取り出し」を参照してください。複数行の取り出しの詳細は、6-35
ページの「複数行の取り出し」を参照してください。
第 6 章 データ処理
6-1
サポートするデータ型
INSERT を使ってテーブルに新規データを書き込む方法の詳細は、6-54 ページの「データ
の挿入」を参照してください。UPDATE を使ってデータを修正するには、6-60 ページの
「データの更新」を参照してください。DELETE を使ってテーブルからデータを削除するに
は、6-65 ページの「データの削除」を参照してください。
サポートするデータ型
表に対して書き込みまたはクエリーするには、表の構造(含まれる列の種類、列に対して
定義されたデータ型の種類)を把握している必要があります。InterBase では次の表で説明
するとおり、13 種類の基本データ型をサポートします。
表 6.1
InterBase でサポートするデータ型
名前
サイズ
範囲と精度
説明
BLOB
可変
• なし
• グラフィック、テキスト、デジタ
• BLOB セグメント サイズは 64 KB に
制限されます。
ル化した音声などのデータを格納
する場合に使用する動的にサイズ
を変更できるデータ型。
• 基本構造単位はセグメントです。
• Blob のサブタイプでは BLOB の内
容を示します。
BOOLEAN
16 ビット
• TRUE
• FALSE
CHAR(n)
n 文字
• 有効な値 は、TRUE、FALSE、およ
び UNKNOWN を返します。
• UNKNOWN
• ODS 11 以降、任意の dialect が必要
• 1 ~ 32,767 バイト
• 固定長の CHAR またはテキスト文
• キャラクタ セットの文字サイズによ
り 32 KB に収まる最大文字数が決ま
• 代替キーワード:CHARACTER
です。
字列型
ります。
DATE
32 ビット
A.D.100 年 1 月 1 日~ A.D.32768 年 2 月 29
ISC_DATE
日
DECIMAL (precision, scale)
可変
(16、32、
64 ビット)
• precision = 0 ~ 18、格納する精度の最
小桁数 precision を指定します。
• scale = 0 ~ {value}、格納する小数点以
下の桁数を指定します。
• 小数点以下 scale 桁の数値。例:
DECIMAL(10, 3) の場合には、
数値の
フォーマットは ppppppp.sss にな
ります。
• Scale は precision 以下である必要があ
ります。
64 ビットa
2.225 x 10-308 ~ 1.797 x 10308
IEEE 倍精度:15 桁
FLOAT
32 ビット
1.175 x 10-38 ~ 3.402 x 1038
IEEE 単精度:7 桁
INTEGER
32 ビット
-2,147,483,648 ~ 2,147,483,647
符号付き long(ロングワード)
DOUBLE PRECISION
6-2 埋 め 込 み S Q L ガ イ ド
サポートするデータ型
表 6.1
InterBase でサポートするデータ型 ( 続き )
名前
サイズ
範囲と精度
説明
可変
• precision = 0 ~ 18、格納する正確な精
度の桁数 precision を指定します。
• 小数点以下 scale 桁の数値。例:
NUMERIC(10, 3) の場合には、数値
のフォーマットは ppppppp.sss に
NUMERIC (precision, scale)
(16、32、
64 ビット)
• scale = 0 ~ {value}、格納する小数点以
下の桁数を指定します。
なります。
• Scale は precision 以下である必要があ
ります。
SMALLINT
16 ビット
-32,768 ~ 32,767
符号付き short(ワード)
TIME
32 ビット
00:00:00.0000 ~ 23:59:59.9999
ISC_TIME
TIMESTAMP
64 ビット
A.D.100 年 1 月 1 日~ A.D.32768 年 2 月 29
ISC_TIMESTAMP; には、日付と時間情
日
報の両方が含まれます。
• 1 ~ 32,765 バイト
• 可変長の CHAR またはテキスト文
VARCHAR (n)
n 文字
• キャラクタ セットの文字サイズによ
り 32 KB に収まる最大文字数が決ま
ります。
a.
字列型
• 代替キーワード:CHAR VARYING、
CHARACTER VARYING
DOUBLE の実際のサイズはプラットフォームで変わります。多くのプラットフォームでは 64 ビット サイズをサポー
トします。
BLOB データ型は、決まったサイズを持たない、また可変長の大量のデータを格納すること
ができます。この種のデータとしては、たとえば、ビットマップのグラフィックイメージ、
ベクター描画、サウンドファイル、小冊子や書籍の大きさの文書、マルチメディア関連の
データなどがあります。このように、BLOB ではさまざまな型のデータを扱えますが、反面、
データの読み取りと書き込みに適した処理が必要になります。BLOB の処理の詳細は、第 8
章「BLOB データの操作」を参照してください。
InterBase の DATE、TIME、および TIMEWSTAMP データ型をプログラムで扱う場合にも変
換が必要になります。日付の取り出しと書き込みの詳細は、第 7 章「日付と時刻」を参照
してください。
InterBase では、各種データ型の配列もサポートされています。配列とは複数のデータで構
成されるマトリクスを言います。配列には、BLOB を除き、InterBase がサポートしている
各種のデータを置くことができます。配列は、配列全体を 1 つのデータとして扱うことも
でき、データを個別に操作することもできます。配列を使って状況に応じたデータアクセス
を行うには、第 9 章「配列の使い方」を参照してください。
InterBase のデータ型の詳細は、
『データ定義ガイド』を参照してください。
メモ
InterBase では、評価結果が FALSE になる " リテラル < 関係演算子 > リテラル " 形式の論理
式を探し、FALSE 論理式の反転ノードを返すことで、データ検索を省略します。
第 6 章 データ処理
6-3
SQL 式
SQL 式
SQL のデータ操作文では、どの文でも SQL 式を使用できます。式とは、列、定数、変数の
比較、評価に利用できる SQL 構文を指します。また、式による比較や評価の結果、1 つの
値が返されます。
たとえば、SELECT 文では WHERE 句を記述でき、この WHERE 句には検索条件を指定しま
す。この検索条件によりデータ取り出しの際の行が識別されます。この検索条件が SQL の
式の 1 つです。また、DELETE や UPDATE でも検索条件の指定が可能です。式が検索条件の
場合、通常その式の結果は論理値(TRUE、FALSE、UNKNOWN)で返されます。
SQL の式は、このほか、INSERT 文の VALUE 句、UPDATE 文の SET 句でも記述できます。
これらの句では、式を使用して、計算した値を列に挿入することができます。このように、
式を使って数値を挿入したり更新する場合、通常、算術式の形式で式を記述します。たと
えば、特定の値に別の値を掛ける算術式を記述することで、その結果を列に挿入したり、既
存のデータを計算後の値に更新することができます。また、挿入したり更新するデータが文
字列のときは、式は 2 つの文字列の連結(結合)式になります。この式によって、連結さ
れた 1 つの文字列が列に挿入されたり、既存のデータがその文字列に更新されることにな
ります。
式には、次の表にあるような要素(記号や演算子)を使用できます。
表 6.2
SQL 式の構成要素
要素
説明
列名
指定されているテーブル中の列名で、この指定された列のデータを
もとに値の検索や比較、または、値の計算が行われます。
ホスト言語変数
プログラムで使用されている変数で、格納されている値は変更可能
です。なお、変数は必ず先頭にコロン(:)を付けなければなりません。
定数
ハードコードされた数値または引用符で囲まれた文字列です。たと
えば、507 や “Tokyo” が該当します。
連結演算子
|| です。文字列を結合する際に使用します。
算術演算子
+、–、*、/ です。複数の値の計算や評価に使用します。
論理演算子
NOT、AND、OR の 3 つのキーワードがあり、検索条件で使用します。
いずれか 1 つを使って簡単な検索もでき、複数を組み合わせて複雑
な検索を行うこともできます。論理演算子では、結果が TRUE(真)
または FALSE(偽)で返ります。通常、検索条件以外では使用しませ
ん。
比較演算子
<、>、<=、>=、=、<> で、演算子を挟んで左の値と右の値との比較
が行われます。比較演算子では、結果は TRUE(真)または FALSE
(偽)で返されます。
こ の ほ か、特 殊 な 比 較 演 算 子 と し て、ALL、ANY、BETWEEN、
CONTAINING、EXISTS、IN、IS [NOT] NULL、LIKE、SINGULAR、SOME、
STARTING WITH があります。これらの比較演算子では、結果が TRUE
(真)、FALSE(偽)、UNKNOWN(不定)のいずれかで返されます。
比較演算子は、通常、検索条件でのみ使用されます。
6-4 埋 め 込 み S Q L ガ イ ド
SQL 式
表 6.2
SQL 式の構成要素 ( 続き )
要素
説明
COLLATE 句
CHAR または VARCHAR の値の比較では、COLLATE 句が必要になる
ことがあります。この句を使用して、比較の際の文字の照合順序を
設定できます。
ストアドプロシージャ
再利用可能な SQL 文ブロックです。ストアドプロシージャを使って
パラメータの受け渡しが可能です。ストアドプロシージャは、デー
タベースのメタデータとして格納されています。
サブクエリー
通常、WHERE 句の中にネストされている SELECT 文を指し、メイン
の SELECT 文により検索された行に対して比較を行い、比較結果値を
返したり、計算を行ったりします。
かっこ
複数の式をグループ化し、優先順位を設定するために使用します。
かっこの内側の式は、外側の式より優先して処理されます。複数の
かっこをネストすると、最も内側のかっこ内の式が最初に処理され、
内側の式から外側へと順に処理されます。
日付リテラル
文字列値です。単引用符で囲んで入力でき、SELECT、INSERT、およ
び UPDATE 処理で日付値として解釈されます。使用できる文字列に
は、‘TODAY’、‘NOW’、‘YESTERDAY’、‘TOMORROW’ があります。
USER 疑似列
現在ログインしているユーザー名を参照します。たとえば、USER は、
列の定義において、デフォルトとして使用できます。または、INSERT
に現在のユーザー名を入力する場合に使用できます。ユーザー名が
SELECT 文と DELETE 文で USER を使って参照
テーブルにある場合は、
できます。
簡単な式を複数組み合わせることで、複雑な式を各種作成することができます。たとえば、
次の WHERE 句は、列名が 1 つ、定数が 3 つ、比較演算子が 3 つ、かっこでグループ化し
た式が 1 つ、という複雑な構成の式の例です。この WHERE 句では、給与が 60,000 ドルを
超えていて 120,000 ドル未満の範囲にある社員の行がすべて取り出されます。
WHERE DEPARTMENT = 'Publications' AND
(SALARY > 60000 AND SALARY < 120000)
また、WHERE 句では、検索条件の中に、ネストされた SELECT 文(サブクエリー)を記述
することがあります。たとえば、次の例は、WHERE 句に集計関数 AVG() を使用しているク
エリーです。このクエリーでは、給与を部署別で見た場合、その給与が全部署の平均値よ
り高い部署がすべて取り出されます。
EXEC SQL
DECLARE WELL_PAID CURSOR FOR
SELECT DEPT_NO
INTO :wellpaid
FROM DEPARTMENT
WHERE SALARY > (SELECT AVG(SALARY) FROM DEPARTMENT);
サブクエリーを使って検索条件を指定する方法の詳細は、6-51 ページの「サブクエリー」
を参照してください。集計関数の詳細は、6-21 ページの「集合列のデータの取り出し」を
参照してください。
第 6 章 データ処理
6-5
SQL 式
式での文字列演算子の使い方
文字列演算子(連結演算子とも呼びます)である || を使用して、個別に分かれた複数の文
字列を 1 つの文字列に結合することができます。この場合の文字列は、文字定数でも列に置
かれている値(文字列)でもかまいません。連結演算子の使い方は、次のようになります。
次に例を示します。
char strbuf[80];
. . .
EXEC SQL
SELECT LAST_NAME || ' is the manager of publications.'
INTO :strbuf
FROM DEPARTMENT, EMPLOYEE
WHERE DEPT_NO = 5900 AND MNGR_NO = EMP_NO;
文字列演算子は、次のように INSERT や UPDATE でも使用できます。
EXEC SQL
INSERT INTO DEPARTMENT (MANAGER_NAME)
VALUES(:fname || :lname);
式での算術演算子の使い方
式で数値の計算に使用できる算術演算子として、InterBase では次の 4 種類があります。
表 6.3
算術演算子
演算子
用途
優先順位
演算子
用途
優先順位
*
乗算
1
+
加算
3
/
除算
2
–
減算
4
算術演算子が複数記述されている場合、通常、左から右へと順に処理されます。ただし、優
先順位が異なるものが順不同に混在しているときは、上記の表の優先順位にしたがって算
術演算子が実行されます(たとえば、乗算は除算より先に、除算は減算より先に行われる)。
また、式に算術演算、比較演算、論理演算が混在しているときは、算術演算が最初に実行
されます。この計算の実行順は、かっこで括ることにより変更できます。これで、かっこで
括った部分が、最初に処理されることになります。なお、かっこの部分にさらにネストされ
た部分があるときは、内側の部分から順に計算が行われます。優先順位とかっこを使ってグ
ループ化を行う方法の詳細は、6-14 ページの「演算子の優先順位」を参照してください。
たとえば、次は、WHERE 句の検索条件で算術演算子を使用している例です。ここでは、ま
ず、算術演算子を使って 2 つの列の値を加算した後、比較演算子を使って結果が 10 を超え
るかどうかを確認しています。
DECLARE RAINCITIES CURSOR FOR
SELECT CITYNAME, COUNTRYNAME
INTO :cityname, :countryname
FROM CITIES
6-6 埋 め 込 み S Q L ガ イ ド
SQL 式
WHERE JANUARY_RAIN + FEBRUARY_RAIN > 10;
式での論理演算子の使い方
論理演算子は左側と右側の 2 つの簡単な検索条件を比較する場合に利用します。比較の結
果は、論理値である TRUE(真)、FALSE(偽)、UNKNOWN(不定)のいずれかで返され
ます。InterBase では NOT、AND、OR の 3 種類の論理演算子が認識されます。
NOT は、通常、検索条件の前に記述し、この場合、検索条件の働きが逆転します。一方、
AND と OR は、2 つの簡単な検索条件の間に置きます。たとえば、NOT を使った次のクエ
リーでは、姓が Smith ではない社員がすべて取り出されます。
DECLARE NOSMITH CURSOR FOR
SELECT LAST_NAME
INTO :lname
FROM EMPLOYEE
WHERE NOT LNAME = 'Smith';
これに対して、AND を 2 つの検索条件の間に記述した場合は、両方の検索条件に適合する
ときに行が取り出されます。たとえば、次のクエリーでは、姓が Smith と Jones のどちらで
もない社員が取り出されます。
DECLARE NO_SMITH_OR_JONES CURSOR FOR
SELECT LAST_NAME
INTO :lname
FROM EMPLOYEE
WHERE NOT LNAME = 'Smith' AND NOT LNAME = 'Jones';
OR では、2 つの検索条件のうち 1 つが満足すれば、行が取り出されます。次のクエリーで
は、姓が Smith と Jones のいずれかに該当すれば、その社員の行(姓と名)が取り出されます。
DECLARE ALL_SMITH_JONES CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
INTO :lname, :fname
FROM EMPLOYEE
WHERE LNAME = 'Smith' OR LNAME = 'Jones';
異なる種類の論理演算子が使用されているときは、各検索条件は、記述されている論理演
算子の優先順位にしたがって実行されます。この場合、NOT の検索条件が最初に、続いて
AND、OR の順で処理が行われます。なお、かっこを使用することで、優先順位の変更が可
能です。優先順位とかっこを使ってグループ化を行う方法の詳細は、6-14 ページの「演算
子の優先順位」を参照してください。
式での比較演算子の使い方
比較演算子は、左側の値と右側の値または範囲の間の関係を検査するのに利用できます。結
果は、論理値である TRUE(真)、FALSE(偽)、UNKNOWN(不定)のいずれかで返され
ます。比較演算子では、比較対象の値はどちらも同じデータ型でなければなりません。な
お、双方の値のデータ型が異なる場合は、CAST() 関数を使ってデータ型を変換できます。
また、値としては、列名、定数、計算値を使用できます。
第 6 章 データ処理
6-7
SQL 式
次の表では、文に使用できる演算子、それらの演算子の使い方、およびその使用例につい
て説明します。
メモ
比較演算子による演算で値が NULL だった場合、UNKNOWN が返されます。
CAST() の詳細は、6-17 ページの「CAST() によるデータ型の変換」を参照してください。
一般の比較演算子のほか、InterBase では、特殊な比較演算子も用意されています。この種
の比較演算子では、演算子の右側にサブクエリーを置き、そのサブクエリーの結果と左側
の値の比較が可能です。こういった特殊な比較演算子および処理内容は、次の表のとおりで
す。
表 6.4
サブクエリーを必要とする InterBase の比較演算子
演算子
用途
ALL
左側の値が、サブクエリーから返される値全部と比較され、その全部の
値が条件を満足すると処理が行われます。
ANY および
SOME
左側の値が、サブクエリーから返される値全部と比較され、その中のい
ずれかの値が条件を満足すると処理が行われます。
EXISTS
サブクエリーから返された値の中に、列の値と同じものが少なくとも 1
つあれば処理が行われます。
SINGULAR
サブクエリーから返された値の中に、列の値と同じものがあり、それが
1 つだけであれば処理が行われます。
サブクエリーの使い方の詳細は、6-51 ページの「サブクエリー」を参照してください。
BETWEEN の使い方
BETWEEN では、値が一定の範囲に収まるかどうかを調べます。BETWEEN 演算子の正規の
構文は次のとおりです。
<value> [NOT] BETWEEN <value> AND <value>
たとえば、次のカーソル宣言では、給与が 100,000 ドル以上 250,000 ドル以下の範囲にある
社員について、LAST_NAME と FIRST_NAME の 2 つの列のデータが取り出されます。
EXEC SQL
DECLARE LARGE_SALARIES CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE SALARY BETWEEN 100000 AND 250000;
また、NOT BETWEEN では、値が指定した範囲の外にあるかどうかを調べます。たとえば、
次のカーソル宣言では、給与が 30,000 ドル未満の社員、および 150,000 ドルを超える社員に
ついて、LAST_NAME と FIRST_NAME の 2 つの列のデータが取り出されます。
EXEC SQL
DECLARE EXTREME_SALARIES CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE SALARY NOT BETWEEN 30000 AND 150000;
6-8 埋 め 込 み S Q L ガ イ ド
SQL 式
CONTAINING の使い方
CONTAINING では、左側の値として ASCII 文字列、右側の値として引用符で囲んだ ASCII
文字列を記述します。これで、左側の ASCII 文字列の中に右側の ASCII 文字列が含まれて
いるかどうかが検査されます。なお、CONTAINING では、大文字と小文字が区別されませ
ん。つまり、“String”、“STRING”、“string” はいずれも同じ値と見なされます。ダイアレク
ト 3 のデータベースとクライアントでは、文字列は単引用符で囲まなければなりません。
CONTAINING の正規の構文は次のとおりです。
<value> [NOT] CONTAINING '<string>'
たとえば、次のカーソル宣言では、姓名の中に "las"(大文字と小文字は区別されないので、
"LAS" と "Las" も該当)という文字列が含まれているという条件に一致する社員名がすべて
取り出されます。
EXEC SQL
DECLARE LAS_EMP CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE LAST_NAME CONTAINING 'las';
指定した文字列が含まれていない行を検索する場合は、NOT CONTAINING を使用します。
たとえば、次のカーソル宣言では、姓名の中に “las”(“LAS” と “Las” も該当)という文字
列が含まれていない社員名がすべて取り出されます。
EXEC SQL
DECLARE NOT_LAS_EMP CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE LAST_NAME NOT CONTAINING 'las';
ヒント
CONTAINING は、BLOB データ中の引用符で囲まれた文字列の検索にも利用できます。こ
の場合、セグメント単位で検索されます。
IN の使い方
IN では、左側の値が、右側に記述した複数の値の中にあるかどうかを検査することができ
ます。IN の場合、右側の値はそれぞれカンマで区切り、かっこで囲みます。IN を使用する
ときは、必ず、この書式が必要になります。なお、左側の値が NULL の場合は、UNKNOWN
が返されます。
IN の構文は次のとおりです。
<value> [NOT] IN (<value> [, <value> ...])
たとえば、次のカーソル宣言では、"Accounting"、"Payroll"、"Human Resources" のいずれ
かの部署に所属する社員名がすべて取り出されます。
EXEC SQL
DECLARE ACCT_PAY_HR CURSOR FOR
SELECT DEPARTMENT, LAST_NAME, FIRST_NAME, EMP_NO
FROM EMPLOYEE EMP, DEPTARTMENT DEP
WHERE EMP.DEPT_NO = DEP.DEPT_NO AND
DEPARTMENT IN ('Accounting', 'Payroll', 'Human Resources')
GROUP BY DEPARTMENT;
第 6 章 データ処理
6-9
SQL 式
右側に指定した複数の値に該当しない値を持つ行を検索するときは、NOT IN を使用しま
す。たとえば、次のカーソル宣言では、"Accounting"、"Payroll"、"Human Resources" 以外
の部署に所属する社員の名前がすべて取り出されます。
EXEC SQL
DECLARE NOT_ACCT_PAY_HR CURSOR FOR
SELECT DEPARTMENT, LAST_NAME, FIRST_NAME, EMP_NO
FROM EMPLOYEE EMP, DEPTARTMENT DEP
WHERE EMP.DEPT_NO = DEP.DEPT_NO AND
DEPARTMENT NOT IN ('Accounting', 'Payroll',
'Human Resources')
GROUP BY DEPARTMENT;
IN では、左側に複数の値のかわりにサブクエリーを置き、その結果をもとに比較を行うこ
ともできます。たとえば、次のカーソル宣言では、ヨーロッパにある都市がすべて取り出さ
れます。
EXEC SQL
DECLARE NON_JFG_CITIES CURSOR FOR
SELECT C.COUNTRY, C.CITY, C.POPULATION
FROM CITIES C
WHERE C.COUNTRY NOT IN (SELECT O.COUNTRY FROM COUNTRIES O
WHERE O.CONTINENT <> 'Europe')
GROUP BY C.COUNTRY;
サブクエリーの使い方の詳細は、6-51 ページの「サブクエリー」を参照してください。
LIKE の使い方
LIKE では、右側にワイルドカードを含む文字列を指定します。左側の文字列は、このワイ
ルドカードを含む文字列と比較されることになります。比較では、大文字と小文字は区別
されます。なお、ワイルドカードとは単一の文字または文字列を表す記号で、任意の文字
または文字列を代行する働きを持っています。LIKE では、次の 2 種類のワイルドカードを
使用できます。
• %(パーセント記号)
:複数の文字(文字がない場合も含む)で構成される任意の文字列を
表します。
• _(下線記号)
:単一の任意の文字を表します。
LIKE の構文は次のとおりです。
<value> [NOT] LIKE <value> [ESCAPE 'symbol']
たとえば、次のカーソル宣言では、姓の中に "ton"(大文字と小文字が区別されるので、"Ton"
は除外されます)という 3 文字を含んでいる社員のデータが取り出されます。
EXEC SQL
DECLARE TON_EMP CURSOR FOR
SELECT LAST_NAME, FIRST_NAME, EMP_NO
FROM EMPLOYEE
WHERE LAST_NAME LIKE '%ton%';
なお、場合によっては、検索対象の文字列にパーセント記号や下線が含まれていることが
あります。このように文字列を検索する場合は、次のようにします。
6-10 埋 め 込 み S Q L ガ イ ド
SQL 式
1
2
% または _ の右になんらかの記号(次の例では @)を記述します。
ESCAPE 句で、その記号(エスケープ文字)を指定します(次の例では @)
。これで、
エスケープ文字の右隣の文字がワイルドカードではなくリテラルシンボル(実際の文
字)であると解釈されるようになります。つまり、エスケープ文字の右の文字が検索対
象に含まれることになります。
たとえば、次のカーソル宣言では、RDB$RELATIONS のテーブル名のうち、下線が含まれ
ているテーブル名がすべて取り出されます。
EXEC SQL
DECLARE UNDER_TABLE CURSOR FOR
SELECT RDB$RELATION_NAME
FROM RDB$RELATIONS
WHERE RDB$RELATION_NAME LIKE '%@_%' ESCAPE '@';
NOT LIKE を使用すると、上とは逆の形で行を取り出すこともできます。たとえば、次の例
では、RDB$RELATIONS のテーブル名のうち、下線が含まれていないテーブル名がすべて
取り出されます。
EXEC SQL
DECLARE NOT_UNDER_TABLE CURSOR FOR
SELECT RDB$RELATION_NAME
FROM RDB$RELATIONS
WHERE RDB$RELATION_NAME NOT LIKE '%@_%' ESCAPE '@';
IS NULL の使い方
IS NULL を使用して、列の値が存在しない行を取り出すことができます。IS NULL の正規
の構文は次のようになります。
<value> IS [NOT] NULL
たとえば、次は、電話(内線)を持っていない社員名を取り出す記述例です。
EXEC SQL
DECLARE MISSING_PHONE CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE PHONE_EXT IS NULL;
逆に、列の値が存在する行を拾いたいときは、IS NOT NULL を使用します。たとえば、電
話(内線)を持っている社員名を取り出すには次のように入力します。
EXEC SQL
DECLARE PHONE_LIST CURSOR FOR
SELECT LAST_NAME, FIRST_NAME, PHONE_EXT
FROM EMPLOYEE
WHERE PHONE_EXT IS NOT NULL
ORDER BY LAST_NAME, FIRST_NAME;
第 6 章 データ処理
6-11
SQL 式
STARTING WITH の使い方
STARTING WITH では、先頭の文字列を指定し、その文字列で始まる値を検索することが
できます。この場合、大文字と小文字が区別されます。また、照合順序が指定されている場
合は、そのバイト一致規則が使用されるため、異なる言語のキャラクタセットも変換可能
です。STARTING WITH の正規の構文は次のとおりです。
<value> [NOT] STARTING WITH <value>
たとえば、次のカーソル宣言では、姓が "To" で始まる社員がすべて取り出されます。
EXEC SQL
DECLARE TO_EMP CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE LAST_NAME STARTING WITH 'To';
指定した文字列以外で始まるデータを取り出すには、NOT STARTING WITH を使用します。
たとえば、姓が “To” 以外で始まる社員名を取り出す場合、次のように記述します。
EXEC SQL
DECLARE NOT_TO_EMP CURSOR FOR
SELECT LAST_NAME, FIRST_NAME
FROM EMPLOYEE
WHERE LAST_NAME NOT STARTING WITH 'To';
照合順序とバイト一致規則の詳細は、『データ定義ガイド』を参照してください。
ALL の使い方
ALL では、列の値と、サブクエリーにより返される複数の値がすべて比較され、その結果、
条件が満たされれば列の値が取り出されます。ALL の正規の構文は次のとおりです。
<value> <comparison_operator> ALL (<subquery>)
たとえば、次のカーソル宣言では、流通ルート販売部の社員全員の給与がすべて検査され、
列の値がどの給与より高かった場合、その列の値が取り出されます。ここでは、流通ルー
ト販売部の最高給与(通常は部長の給与が最高)を超える給与の社員名が取り出されます。
EXEC SQL
DECLARE MORE_THAN_VP CURSOR FOR
SELECT LAST_NAME, FIRST_NAME, SALARY
FROM EMPLOYEE
WHERE SALARY > ALL (SELECT SALARY FROM EMPLOYEE
WHERE DEPT_NO = 7734);
サブクエリーによりなんらかの値が返された場合、その値が NULL だったときは、ALL は
UNKNOWN を返します。逆に、比較対象の値(列の値)が NULL で、サブクエリーにより
返される値が NULL 以外のときも、ALL は UNKNOWN を返します。一方、比較対象の値
が NULL で、サブクエリーにより返される値が空のセット(すべて NULL)だったときは、
ALL は TRUE(真)を返します。
サブクエリーの使い方の詳細は、6-51 ページの「サブクエリー」を参照してください。
6-12 埋 め 込 み S Q L ガ イ ド
SQL 式
ANY および SOME の使い方
ANY と SOME では、サブクエリーにより返される複数の値のうち、条件に一致するものが
あれば、列の値が取り出されます。ANY の正規の構文は次のとおりです。
<value> <comparison_operator> ANY | SOME (<subquery>)
たとえば、次のカーソル宣言では、流通ルート販売部の社員全員の給与が検査され、列の
値が、その中の給与より高かった場合、その列の値が取り出されます。したがって、ここ
では、流通ルート販売部の最低給与を超える給与の社員名が取り出されます。
EXEC SQL
DECLARE MORE_CHANNEL CURSOR FOR
SELECT LAST_NAME, FIRST_NAME, SALARY
FROM EMPLOYEE
WHERE SALARY > ANY (SELECT SALARY FROM EMPLOYEE
WHERE DEPT_NO = 7734);
サブクエリーによりなんらかの値が返された場合、その値が NULL だったときは、ANY と
SOME は UNKNOWN を返します。逆に、比較対象の値(列の値)が NULL で、サブクエ
リーにより返される値が NULL 以外のときも、ANY と SOME は UNKNOWN を返します。
一方、比較対象の値が NULL で、サブクエリーにより返される値が空のセット(すべて
NULL)だったときは、ANY と SOME は FALSE を返します。
サブクエリーの使い方の詳細は、6-51 ページの「サブクエリー」を参照してください。
EXISTS の使い方
EXISTS では、列のデータについて、サブクエリーで指定された検索条件を満足する行が別
のテーブル中に少なくとも 1 つあれば、列のデータが取り出されます。すべての列を選択す
るには、サブクエリーの SELECT 句に *(アスタリスク)を記述します。EXISTS の正規の
構文は次のとおりです。
[NOT] EXISTS (SELECT * FROM <tablelist> WHERE <search_condition>)
次は、河川がある国をすべて取り出す場合の記述です。
EXEC SQL
DECLARE RIVER_COUNTRIES CURSOR FOR
SELECT COUNTRY
FROM COUNTRIES C
WHERE EXISTS (SELECT * FROM RIVERS R
WHERE R.COUNTRY = C.COUNTRY);
また、NOT EXISTS を使用すると、サブクエリーで指定した条件に該当しない行のデータが
取り出されます。たとえば、次の例では、河川のない国が取り出されます。
EXEC SQL
DECLARE NON_RIVER_COUNTRIES COUNTRIES FOR
SELECT COUNTRY
FROM COUNTRIES C
WHERE NOT EXISTS (SELECT * FROM RIVERS R
WHERE R.COUNTRY = C.COUNTRY);
EXISTS では、NULL 値の場合でも必ず、TRUE(真)または FALSE(偽)が返されます。
第 6 章 データ処理
6-13
SQL 式
サブクエリーの使い方の詳細は、6-51 ページの「サブクエリー」を参照してください。
SINGULAR の使い方
SINGULAR では、列のデータについて、サブクエリーで指定された検索条件を満足する行
が別のテーブル中に 1 つだけあれば、列のデータが取り出されます。すべての列を選択する
には、サブクエリーの SELECT 句に *(アスタリスク)を記述します。SINGULAR の正規
の構文は次のとおりです。
[NOT] SINGULAR (SELECT * FROM <tablelist> WHERE <search_condition>)
次は、首都が 1 つだけの国を取り出すカーソル宣言の例です。
EXEC SQL
DECLARE SINGLE_CAPITAL CURSOR FOR
SELECT COUNTRY
FROM COUNTRIES COU
WHERE SINGULAR (SELECT * FROM CITIES CIT
WHERE CIT.CITY = COU.CAPITAL);
また、NOT SINGULAR を使用すると、サブクエリーで指定した条件に該当しない行のデー
タが取り出されます。たとえば、次の例では、首都が複数ある国が取り出されます。
EXEC SQL
DECLARE MULTI_CAPITAL CURSOR FOR
SELECT COUNTRY
FROM COUNTRIES COU
WHERE NOT SINGULAR (SELECT * FROM CITIES CIT
WHERE CIT.CITY = COU.CAPITAL);
サブクエリーの使い方の詳細は、6-51 ページの「サブクエリー」を参照してください。
演算子の優先順位
文中で演算子および演算子に関係する数値が評価される順番を優先順位と言います。演算
子の優先順位としては、次の 2 種類があります。
• 異なる種類の演算子間での優先順位
• 同じ種類の演算子間での優先順位
6-14 埋 め 込 み S Q L ガ イ ド
SQL 式
演算子間での優先順位
異なる種類の演算子
InterBase で使用できる演算子の種類は次の表のとおりです。演算子は、表の上の方に記載
されている種類から順に評価されます(文字列演算子が優先順位が最も高く、論理演算子
が優先順位が最も低くなる)。
表 6.5
演算子の種類別優先順位
演算子の種類
優先順位
摘要
文字列
1(最上位)
他の種類の演算子があっても、文字列演算子が最も先に実行さ
れ 2 つの文字列が連結されます。
算術演算子
?
算術演算子は、文字列演算子の次に実行されます。ただし、比
較演算子と論理演算子より優先順位は上です。
比較演算子
?
比較演算子は、文字列演算子および算術演算子の次に実行され
ます。ただし、論理演算子より優先順位は上です。
論理演算子
3(最下位)
論理演算子は、上記の 3 種類の演算子が実行された後で実行さ
れます。
同じ種類の演算子
式に同じ種類の演算子が複数記述されている場合、各演算子は左から右へと順に評価され
ます。ただし、同一の値に対して 2 つの演算子の両方が働く場合、この規則は適用されま
せん。
たとえば、3 + 2 * 6 という数式があったとすると、加算演算子と乗算演算子の両方が同一の
値である 2 に働くことになります。この場合、原則どおり左から右へ計算が行われると、3
+ 2 = 5、5 * 6 = 30 で答えは 30 となります。3+ 2 = 5; 5 * 6 = 30. これでは不都合が生じるため、
InterBase では、通常の数式の規則にしたがって、自動的に乗算が先に実行されます。つま
り、2 * 6 = 12、3 + 12 = 15 という結果が得られます。
次の表は、算術演算子を評価順の高いものから低いものにしたがって一覧にしたものです。
表 6.6
算術演算子の優先順位
演算子
優先順位
摘要
*
1(最上位)
乗算は、他の 3 つの算術演算子に先立って実行されます。
/
?
除算は、加算と減算に先立って実行されます。
+
?
加算は、減算の前に実行されます。
–
3(最下位)
減算は、他の 3 つの算術演算子による計算が終わってから実行されま
す。
第 6 章 データ処理
6-15
SQL 式
比較演算子も、通常は左から右へと実行されますが、算術演算子と同様に演算子同士の競
合が起こることもあります。このような場合のために、InterBase では比較演算子を評価す
る際の規則が設けられています。次の表は、比較演算子の評価順を一覧したものです。評価
順は上が高く、下が低くなっています。
表 6.7
比較演算子の優先順位
演算子
優先順位
摘要
=, ==
1(最上位)
等号演算子は、どの演算子よりも先に評価されます。
<>, !=, ~=, ^=
?
>
?
<
?
>=
?
<=
?
!>, ~>, ^>
?
!<, ~<, ^<
3(最下位)
より小さくない演算子は、他の演算子の処理が終わっ
てから最後に評価されます。
上記の比較演算子と、ALL、ANY、BETWEEN、CONTAINING、EXISTS、IN、LIKE、NULL、
SINGULAR、SOME、STARTING WITH といった特殊比較演算子が混在しているときは、通
常どおり左から右へと評価されます。ただし、両者で競合が起こったときは、まず、通常
の比較演算子が評価され、その後で特殊比較演算子が実行されます。なお、特殊演算子同士
が競合した場合、原則どおり、左から右へ評価されます。
また、論理演算子も通常は左から右へと評価されますが、論理演算子同士が競合した場合、
次の表の優先順位にしたがって実行されます。
表 6.8
論理演算子の優先順位
演算子
優先順位
摘要
NOT
1(最上位)
NOT 演算子は、どの論理演算子よりも先に評価されます。
AND
?
NOT 演算子、AND 演算子、OR 演算子の順に評価されます。
OR
3(最下位)
OR 演算子は、3 つの論理演算子のうち最後に評価されます。
演算子の評価順の変更
式で演算子が複数記述されている場合、かっこを使ってグループにまとめることで、演算
子の評価順の変更が可能です。これで、かっこで括った部分が 1 つの単位として評価され
ることになります。この部分で算出された値は、他の演算子で利用されます。たとえば、3
+ 2 * 6 という数式があり、かっこで括らない場合には 15 という結果が出ます。この数式で、
加算を先行させる場合は、次のようにしてかっこで括ります。
(3 + 2) * 6 = 30
6-16 埋 め 込 み S Q L ガ イ ド
SQL 式
ヒント
複雑な式では、左から右へというデフォルトの評価順で問題がなくても、できるだけかっ
こを使って各部をまとめるようにします。明示的にグループ化された式は、見やすく、また
デバッグも楽になります。
CAST() によるデータ型の変換
通常、式で比較または評価できるのは、同じデータ型のデータに限られます。データ型の異
なるデータを式で使用する場合は、CAST() 関数を使用します。この関数を使用することで、
データのデータ型の変換が可能です。CAST() の構文は次のとおりです。
CAST (<value> | NULL AS datatype)
たとえば、次の WHERE 句では、CAST() を使用して、CHAR データ型の INTERVIEW_DATE
を DATE データ型に変換しています。これで、DATE データ型の HIRE_DATE との比較が
可能になります。
WHERE HIRE_DATE = CAST(INTERVIEW_DATE AS DATE);
このように CAST() を使用することで、同じテーブルにデータ型の異なる列があっても比較
が可能です。また、CAST() は、別のテーブルの列に対しても使用できます。CAST() で変換
できるデータ型は次の表のとおりです。
表 6.9
CAST() で変換できるデータ型
変換元
変換先
NUMERIC
CHARACTER、NUMERIC
CHARACTER
DATE、TIME、TIMESTAMP
TIMESTAMP
DATE、TIME、CHARACTER
DATE
TIMESTAMP、CHARACTER
TIME
TIMESTAMP、CHARACTER
BOOLEAN
CHARACTER
データ型を CAST() で指定したデータ型に変換できなかった場合にはエラーとなります。
整 数 以 外 の 数 値 デ ー タ 型 を整数データ型にキャストする場合、CAST() は Delphi の
ROUND(x) のように機能します。x は最も近い整数に丸められ、x が 2 つの整数のちょうど
中間にある場合、結果は絶対値が大きい方の数になります。次に例を示します。
CAST(1.6 as INTEGER) = 2
CAST(-1.5 as INTEGER) = -2
CAST(-1.6 as INTEGER) = -2
UPPER() によるテキストデータの大文字変更
UPPER() を使用して、テキスト(文字)データおよび BLOB のテキストデータを強制的に
大文字にすることができます。UPPER() は、SELECT、INSERT、UPDATE、DELETE の各文
で使用できます。たとえば、会社の部署名は大文字で記憶されていた方が、将来のデータの
第 6 章 データ処理
6-17
SELECT に よ る デ ー タ の 取 り 出 し
取り出しが簡単になります。このような場合、ユーザーが部署名を小文字で入力した際に、
UPPER() を使用して、強制的に大文字にすることができます。次は、INSERT 文で UPPER()
を使用し、ユーザーの入力文字を大文字に変更するコード例です。
EXEC SQL
BEGIN DECLARE SECTION;
char response[26];
EXEC SQL
END DECLARE SECTION;
. . .
printf("Enter new department name: ");
response[0] = '¥0';
gets(response);
if (response)
EXEC SQL
INSERT INTO DEPARTMENT(DEPT_NO, DEPARTMENT)
VALUES(GEN_ID(GDEPT_NO, 1), UPPER(:response));
. . .
また、次の文は、SELECT 文で UPPER() を使用している例です。この例では、データが大
文字に変換されて取り出されるとともに、検索対象が大文字に限定されます。
EXEC SQL
SELECT DEPT_NO, UPPER(DEPARTMENT)
FROM DEPARTMENT
WHERE UPPER(DEPARTMENT) STARTING WITH 'A';
SELECT によるデータの取り出し
SQL でのクエリーは、すべて SELECT 文を使って行います。SELECT では、テーブルの行を
指定して取り出すことも、テーブルの行全部を一括して取り出すこともできます。取り出
しの際は列を指定することもできます。列の指定による取り出しのことを、射影(projection)
と呼んでいます。SELECT にはオプションで検索条件を指定することができます。この検索
条件により、取り出す行の数を限定したり、値が不明の行を取り出すことができます。ま
た、ビューによる行の取り出し、複数のテーブルの行の結合といった作業を行うこともで
きます。
SELECT 文には、最低、次の要素を指定しなければなりません。
• テーブル中の列名:この列からデータが取り出されることになります。 名前は複数列記す
ることもでき、SELECT の右に記述します。
• テーブル名:このテーブルの列から取り出しが行われることになります。FROM 句に記述
します。
SELECT で単一行 SELECT(1 つのテーブルの 1 行、または 1 行の中の任意の列の取り出し)
を行うときは、INTO 句と WHERE 句を記述しなければなりません。このうち、INTO 句で
は変数を指定します。この変数に、取り出されたデータが格納されます。また、WHERE 句
には検索条件を記述します。この場合、検索条件は、列の 1 行だけが検索されるようなも
のでなければなりません。
6-18 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
たとえば、次の SELECT 文では、テーブルの 3 つの列から値(データ)が取り出され、各
値が 3 つの変数に格納されます。
EXEC SQL
SELECT EMP_NO, FIRSTNAME, LASTNAME
INTO :emp_no, :fname, :lname
FROM EMPLOYEE WHERE EMP_NO = 1888;
ヒント
変数は、プログラム中で事前に宣言しておかなければ、SELECT などの SQL 文で使用する
ことはできません。ホスト変数の宣言の詳細は、第 2 章「アプリケーションの必要条件」を
参照してください。
次の表は、SELECT 文で使用できる句の一覧です。なお、句を SELECT で記述する順番は決
まっており、表では、その順番にしたがって掲載してあります。また、単一行 SELECT(1 行
の取り出し)と複数行 SELECT(複数行にわたる取り出し)での使用についても示します。
表 6.10 SELECT 文の句
句
用途
SELECT
抽出する列を一覧します。
INTO
単一行 SELECT で、抽出された列を格納するホスト変数を一覧します。
FROM
テーブルの指定に使用します。このテーブルに対して、取り出しが行
われます。
WHERE
検索条件の指定に使用します。この検索条件により、取り出し対象が
一部の行に限定されます。この WHERE 句には、その WHERE 句だけで
使用される SELECT 文を記述することができます。この文をサブクエ
リーと言います。
GROUP BY
この句を使用して、列の同じデータを基準に行をグループ化すること
ができます。HAVING と併用することができます。
HAVING
GROUP BY によりグループ化された行を、
さらに一部の行に限定するこ
とができます。
UNION
複数の SELECT 文により生成された結果を、行の重複なしに 1 つの動的
なテーブルにまとめることができます。
PLAN
クエリーの方法を指定することができます。通常、クエリーの方法は
クエリー最適化機能により自動的に決められますが、この PLAN を
使って指定することもできます。
第 6 章 データ処理
6-19
SELECT に よ る デ ー タ の 取 り 出 し
表 6.10 SELECT 文の句 ( 続き )
句
用途
ORDER BY
SELECT によって取り出される行のソート順を指定できます。デフォル
トの昇順(ASC)のほか、降順(DESC)が指定できます。
ROWS <value>
[TO <upper_value>]
[BY <step_value>]
[PERCENT][WITH TIES]
• value は、単独で使用される場合は、返される行の総数。
• value は、TO とともに使用される場合は、返される最初の行の番号。
• value は、PERCENT とともに使用される場合は、パーセント。
• upper_value は、返される最後の行。
• step_value = n の場合は、n 行ごとの行を返す。
• value PERCENT は、value=n の場合に、n% の行を返す。
• WITH TIES は、重複行を返す。ORDER BY とともに使用する必要があ
る。
FOR UPDATE
DECLARE CURSOR 文で SELECT 句を使用している場合、FOR UPDATE
を記述することで、SELECT で取り出されたデータが更新可能な状態と
なります。データの更新には、WHERE CURRENT OF 句を使用します。
この各句を SELECT とともに使用する方法については、以下の各節で説明します。これに
引き続いて、SELECT を直接使って単一の行を返す方法、および DECLARE CURSOR 文で
SELECT を使って複数の行を返す方法の詳細について説明します。SELECT 構文についての
概要は、『言語リファレンス』を参照してください。
SELECT での取り出し列の指定
SELECT 文では、SELECT キーワードの右にデータの取り出し元となる列を指定しなければ
なりません。列は 1 つでも複数でもかまいません。この SELECT キーワードと一覧した列を
SELECT 句と呼んでいます。
複数の列の指定
複数の列からデータを取り出す場合、その列名を SELECT の右に指定しなければなりませ
ん。この場合、列のデータは、指定した順に取り出されます。また、列名はそれぞれカン
マで区切らなければなりません。このように、全部の列ではなく任意の列のデータを取り出
す処理を射影と言います。
たとえば、次の SELECT では、3 つの列からデータが取り出されます。
EXEC SQL
SELECT EMP_NO, FIRSTNAME, LASTNAME
INTO :emp_no, :fname, :lname
FROM EMPLOYEE WHERE EMP_NO = 2220;
全部の列の指定
テーブル全部の列からデータを取り出すときは、SELECT の右にアスタリスク(*)を指定
します。これによって何度も列名を指定しなくても済みます。たとえば、次の SELECT 文で
は、EMPLOYEE テーブルの全部の列から 1 行分のデータが取り出されます。
6-20 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
EXEC SQL
SELECT *
INTO :emp_no, :fname, :lname, :phone_ext, :hire, :dept_no,
:job_code, :job_grade, :job_country, :salary, :full_name
FROM EMPLOEE WHERE EMP_NO = 1888;
重要
複数の列を指定する場合、各列について変数を 1 つずつ指定しなければなりません。
DISTINCT による重複データの排除
テーブルによっては、同じ列に同じデータが重複して記憶されていることもあります。ま
た、クエリーによっては、データの確認だけが必要で、重複しているデータを全部取り出
す必要がないこともあります。たとえば、次は、EMPLOYEE テーブルに SMITH という姓の
社員がいるかどうかを調べるためのクエリーです。この場合、SMITH という姓を持つ社員
がすべて取り出されます。
EXEC SQL
DECLARE SMITH CURSOR FOR
SELECT LAST_NAME
FROM EMPLOYEE
WHERE LAST_NAME = 'Smith';
このような場合、SELECT に DISTINCT キーワードを付加してデータを 1 つに絞ることがで
きます。たとえば、次の SELECT 文では、“Smith” という姓の社員が 1 人だけ取り出されま
す。
EXEC SQL
DECLARE SMITH CURSOR FOR
SELECT DISTINCT LAST_NAME
FROM EMPLOYEE
WHERE LAST_NAME = 'Smith';
DISTINCT は、1 つだけ記述すれば、指定した列全部に働きます。
集合列のデータの取り出し
SELECT には、集計関数(aggregate function)を記述することができます。集計関数とは、
クエリーで認識された複数行に対して、列または計算列別になんらかの計算を行い、1 つの
値または総計に関する数値を返すような関数を言います。したがって、各行の値が個別に
取り出されることはありません。InterBase で使用できる集計関数は次のとおりです。
表 6.11 SQL の集計関数
関数
用途
AVG()
複数の値の平均値を計算します。
MIN()
複数の値の最小値を取り出します。
MAX()
複数の値の最大値を取り出します。
SUM()
複数の値の合計を計算します。
COUNT()
クエリーの検索条件に適合する行の数を計算します(WHERE 句で条件を特定)
。
第 6 章 データ処理
6-21
SELECT に よ る デ ー タ の 取 り 出 し
たとえば、次のクエリーでは、EMPLOYEE テーブルに記録されている全社員の平均給与が
返されます。
EXEC SQL
SELECT AVG(SALARY)
INTO :avg_sal
FROM EMPLOYEE;
また、次の SELECT 文では、EMPLOYEE テーブルに対するクエリーで識別された行の総数
が返されます。さらに、社員番号の最大値と最小値、全社員の給与総額も計算されます。
EXEC SQL
SELECT COUNT(*), MAX(EMP_NO), MIN(EMP_NO), SUM(SALARY)
INTO :counter, :maxno, :minno, :total_salary
FROM EMPLOYEE;
なお、集計関数で使用される値が NULL または不定だった場合は、その値が置かれている
行は自動的に計算から除外されます。この自動除外機能により、不定の値があっても、平均
値は正常に計算されます。
メモ
集計関数では、全部の行のほか、複数行をグループ化して値を計算することもできます。こ
のようにして計算された値をグループ集合(group aggregate)値と呼んでいます。グループ
集合の使い方の詳細は、6-30 ページの「GROUP BY による複数行のグループ化」を参照
してください。
複数テーブルを対象とする SELECT 文
SELECT で複数のテーブル(またはビューや選択プロシージャ)からデータを取り出す場
合、各テーブルに同じ名前の列が存在することがあります。このような場合は、SELECT 文
で、同一の列名を識別する記述を行わなければなりません。
複数のテーブルの同一列名を識別するには、SELECT 文で列名の前に識別子を付加します。
この場合、次の 2 とおりの方法があります。
• テーブル名とピリオドを付けます。次に例を示します。
EMPLOYEE.EMP_NO は、EMPLOYEE テーブルの EMP_NO という列を示すことになりま
す。
• テーブル相関名(エイリアス)とピリオドを付けます。たとえば、EMPLOYEE テーブルの
相関名が EMP とすると、EMP.EMP_NO は、EMPLOYEE テーブルの EMP_NO という列を
表します。
テーブル相関名(またはビューや選択プロシージャ)は、SELECT 文の FROM 句で宣言で
きます。相関名の宣言の詳細、およびその使用例は、6-25 ページの「相関名の宣言と使い
方」を参照してください。
トランザクション名の指定
InterBase では、SQL アプリケーションで同時に複数のトランザクションを実行できるよう
に設計されています。ただ、次の条件が必要になります。
• トランザクションがそれぞれ SET TRANSACTION 文で事前に宣言されていること。
6-22 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
• データ操作文(SELECT、INSERT、UPDATE、DELETE)の TRANSACTION 句で、その
つどトランザクション名を指定すること。これで、その文は、指定したトランザクション
のもとで働くことになります。
• SQL 文が動的ではないこと(DSQL 文ではないこと)
。
たとえば、SELECT では、SELECT キーワードの右に TRANSACTION 句(TRANSACTION
とトランザクション名)を記述し、その右に列名を続けます。構文は次のようになります。
SELECT TRANSACTION name <col> [, <col> ...]
なお、最初から最後まで 1 つのトランザクションしか使用しないプログラム、または一度
に 1 つのトランザクションしか起動しないプログラムでは、TRANSACTION 句は記述しな
くてもかまいません。つまり、TRANSACTION 句は、同時に複数のトランザクションを使
用するプログラムに限って必要になります。たとえば、次の SELECT 文は、T1 というトラ
ンザクションとともに機能します。
EXEC SQL
SELECT TRANSACTION T1:
COUNT(*), MAX(EMP_NO), MIN(EMP_NO), SUM(SALARY)
INTO :counter, :maxno, :minno, :total_salary
FROM EMPLOYEE;
トランザクション処理と命名の詳細は、第 4 章「トランザクションの操作」を参照してく
ださい。
INTO での変数の指定
単一行 SELECT(1 つのテーブルの 1 行、または 1 行の中の任意のデータの取り出し)では、
取り出されたデータは変数に格納されます。この変数は、SELECT 文の INTO 句を使って指
定します。この INTO 句は、列名のすぐ後に記述しなければなりません。また、変数の先頭
にはコロン(:)を付加するとともに、列名が複数のときは、各変数をカンマで区切ります。
INTO 句で指定する変数は、事前に宣言しておかなくてはなりません。この宣言により、変
数を使用できるようになります。また、変数の数、順番、データ型は、SELECT で指定した
列の数、順番、データ型と対応するものでなければなりません。数、順番、データ型が違っ
ている場合、オーバーフローやデータ変換エラーが発生します。
たとえば、次の C 言語のコードでは、セクション宣言で、lname、fname、salary という 3 つ
の変数が宣言されています。このうち、lname と fname は文字列として、salary は 32 ビット
整数として宣言されています。SELECT 文では、データの取り出し対象となる列が 3 つ指定
されています。また、INTO 句では、変数が 3 つ指定されており、この 3 つの変数に列の
データがそれぞれ格納されることになります。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
long salary;
char lname[20], fname[15];
EXEC SQL
END DECLARE SECTION;
. . .
EXEC SQL
第 6 章 データ処理
6-23
SELECT に よ る デ ー タ の 取 り 出 し
SELECT LAST_NAME, FIRST_NAME, SALARY
INTO :lanem, :fname, :salary
FROM EMPLOYEE
WHERE LNAME = 'Smith';
. . .
メモ
複数行を取り出す場合は、INTO 句は SELECT 文ではなく FETCH 文とともに使用します。
FETCH 文における INTO 句の詳細は、6-38 ページの「カーソルによる行の取り出し」を参
照してください。
FROM でのテーブルの指定
SELECT 文には、必ず FROM 句を記述しなければなりません。この FROM 句で指定した
テーブル(またはビューや選択プロシージャ)から、データが取り出されることになりま
す。FROM の正規の構文は次のとおりです。
FROM table | view | procedure [alias] [, table | view | procedure [alias] ...]
FROM 句には、テーブル、ビュー、選択プロシージャのいずれかの名前を少なくとも 1 つ
は記述しなければなりません。また、複数のテーブル(またはビュー、選択プロシージャ)
からデータを取り出す場合は、各テーブル名をカンマで区切って一覧します。また、エイ
リアスを使用する場合は、テーブルごとにエイリアスを付加します。選択プロシージャの
詳細は、第 10 章「ストアドプロシージャ」を参照してください。
1 つのテーブルまたはビューの指定
次の例は、FROM 句で 1 つのテーブルを指定する場合の記述です。ここでは、EMPLOYEE
テーブルを指定しており、このテーブルからデータが取り出されることになります。
EXEC SQL
SELECT LAST_NAME, FIRST_NAME, SALARY
INTO :lanem, :fname, :salary
FROM EMPLOYEE
WHERE LNAME = 'Smith';
また、次は、同じ INTO 句を使用して、テーブルではなくビュー(または選択プロシージャ)
をデータの取り出し元として指定している例です。この文では、MVIEW という選択プロ
シージャがデータの取り出し元となっています。MVIEW には姓名が “M” で始まる名前の
マネージャがすべて記録されています。また、WHERE 句で DEPT_NO 列のデータ(部署の
番号)が 430 に限定されており、この結果、1 行だけが取り出されます。
EXEC SQL
SELECT DEPT_NO, LAST_NAME, FIRST_NAME, SALARY
INTO :lname, :fname, :salary
FROM MVIEW
WHERE DEPT_NO = 430;
選択プロシージャの詳細は、第 10 章「ストアドプロシージャ」を参照してください。
複数のテーブルの指定
複数のテーブル(またはビューや選択プロシージャ)からデータを取り出す場合は、その
名前を FROM 句に指定します。名前はそれぞれカンマで区切ります。
6-24 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
なお、データの取り出し元のテーブルが複数の場合、次の状況によって記述の方法が異な
ります。
1
2
同じ名前の列が、他のテーブルにまったくない場合
同じ名前の列が、他のテーブルにもある場合
最初のケースでは、SELECT 句には、通常どおり列名を記述します。たとえば、次のクエ
リーは、DEPARTMENT と EMPLOYEE という 2 つのテーブルからデータを取り出す例で
す。
EXEC SQL
SELECT DEPARTMENT, DEPT_NO, LAST_NAME, FIRST_NAME, EMP_NO
INTO :dept_name, :dept_no, :lname, :fname, :empno
FROM DEPARTMENT, EMPLOYEE
WHERE DEPT_NO = 'Publications' AND MNGR_NO = EMP_NO;
一方、2 番めのケースでは、同じ名前の列が複数のテーブルにあるため、データを取り出す
列を特定することが必要になります。特定するには、テーブル名を先頭に付加し、ピリオ
ドを打った後に列名を続けます。たとえば、次は、DEPARTMENT と EMPLOYEE の両方の
テーブルに EMP_NO という列がある例です。
EXEC SQL
SELECT DEPARTMENT, DEPT_NO, LAST_NAME, FIRST_NAME,
EMLOYEE.EMP_NO
INTO :dept_name, :dept_no, :lname, :fname, :empno
FROM DEPARTMENT, EMPLOYEE
WHERE DEPT_NO = 'Publications' AND
DEPARTMENT.EMP_NO = EMPLOYEE.EMP_NO;
SELECT 句の詳細は、6-20 ページの「SELECT での取り出し列の指定」を参照してくだ
さい。
重要
結合を行うクエリーでは、列名は、相関名を使って指定することができます。相関名、つ
まりエイリアスとは、テーブルに割り当てられた略語で、割り当ては FROM 句で行います。
割り当て後は、他の SELECT 文中で、そのエイリアスを使って列の指定が可能になります。
なお、結合を行わなくても、通常のクエリーで相関名を割り当てて使用することで、複雑
な記述を簡略化することができます。
相関名の宣言と使い方
テーブル名を示す一時変数を相関名(correlation name)またはエイリアス(alias)と言いま
す。相関名で使用できる文字は、英数字、ドル記号($)、下線(_)で、長さは最長で 31 字
までとなっています。なお、相関名は必ず、アルファベットで始めなければなりません。
テーブルを示す相関名を使用することで、長いクエリーでも記述を簡略することができま
す。結合を行う場合は、この相関名を必ず使用しなければなりません。また、複雑なクエ
リーでテーブルを表すのにも利用できます。
相関名は、FROM 句でテーブル名の右に記述しておくと、そのテーブルと関連付けられま
す。以後の文で、その相関名を使って列の指定が可能です。たとえば、それぞれ、
DEPARTMENT テーブルに DEPT、EMPLOYEE テーブルに EMP という相関名を付ける場
合、次のように FROM 句を記述します。
FROM DEPARTMENT DEPT, EMPLOYEE EMP
第 6 章 データ処理
6-25
SELECT に よ る デ ー タ の 取 り 出 し
上記のように、FROM 句で相関名を宣言した後は、SELECT 文でその相関名を使って列を指
定できます。たとえば、次は、検索条件として DEPT と EMP の 2 つの相関名を使って列を
指定しているクエリーの例です。
EXEC SQL
SELECT DEPARTMENT, DEPT_NO, LAST_NAME, FIRST_NAME,
EMLOYEE.EMP_NO
INTO :dept_name, :dept_no, :lname, :fname, :empno
FROM DEPARTMENT DEPT, EMPLOYEE EMP
WHERE DEPT_NO = 'Publications' AND DEPT.EMP_NO = EMP.EMP_NO;
SELECT 句の詳細は、6-20 ページの「SELECT での取り出し列の指定」を参照してくだ
さい。
WHERE での行の絞り込み
クエリーでは、WHERE 句を使用して、行の中に置かれている(または、置かれていない)
データを指定します。これで、そのデータを格納している行が取り出されることになります。
単一行 SELECT、つまり、1 行が取り出されるクエリーでは、WHERE 句は必ず記述しなけ
ればなりません。ただし、FROM 句に選択プロシージャが記述されており、その選択プロ
シージャで返されるのが 1 行の場合は、WHERE 句は必要ありません。
また、SELECT 文が DECLARE CURSOR 文の中に記述されている場合、WHERE 句は記述し
ても省略してもかまいません。WHERE 句を省略したときは、テーブルの全行が取り出され
ます。一方、テーブルの行のうち必要な行だけを取り出すときは、WHERE 句を使用しなけ
ればなりません。
WHERE 句の基本構文は次のとおりです。
WHERE <search_condition>
たとえば、次の簡単な WHERE 句の例は、DEPARTMENT 列に "Publications" というデータ
があるかどうかを検索します。
WHERE DEPARTMENT = 'Publications'
検索条件の基本
WHERE 句では、クエリーでデータを検索するための条件を指定します。このため、WHERE
句に記述した条件を一般に検索条件と呼んでいます。検索条件を指定しておくと、テーブル
の全行に対して、その条件に適合する行がないかどうかの検索が行われます。この後、条件
に適合した行が見つかると、その行が取り出しの該当行として認識されます。
行に対して検索条件による検査が行われた場合、次の 3 つの値のうち、いずれかが返され
ます。
• True:行が WHERE 句で指定されている検索条件に適合した場合、TRUE(真)が返されます。
• False:行が WHERE 句で指定されている検索条件に適合しなかった場合、FALSE(偽)が
返されます。
• Unknown:検査が行われた列の値が不定だった場合、UNKNOWN(不定)が返されます。
これは、値が NULL のため、評価不可能だったことを示します。
6-26 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
検索条件による検索では一般に、その条件がかなり複雑であっても、ほとんどの場合、TRUE
(真)または FALSE(偽)のどちらかとして評価されます。このように、TRUE(真)また
は FALSE(偽)の評価を出す式を論理式と呼んでいます。WHERE 句の検索条件も、この
論理式です。
検索条件の構成要素
ある列の値と定数、または列の値同士で比較を行う、というのが検索条件の最も基本的な
形です。たとえば、次は、DEPARTMENT という列の値と "Publications" という定数を比較
し、この条件に適合する行がないかどうかを検査する WHERE 句の例です。
WHERE DEPARTMENT = 'Publications'
上記の検索条件は、列名、比較演算子(等号)、定数の 3 つの要素で構成されています。な
お、この検索条件は簡単な例で、通常はこれよりも複雑になります。つまり、構成要素の数
も増え、簡単な検索条件がいくつも組み合わされた形になっています。次の表は、検索条
件に使用できる式の要素を示しています。
表 6.12 WHERE 句の検索条件の要素
要素
説明
列名
FROM 句で指定されているテーブル中の列名で、この列に対して値の
検索や比較が行われます。
ホスト言語変数
プログラムで使用されている変数で、格納されている値は変更が可能
です。SELECT で記述する場合、変数には、先頭にコロン(:)を付けな
ければなりません。
定数
ハードコードされた数値または引用符で囲まれた文字列です。たとえ
ば、507 や “Tokyo” が該当します。
連結演算子
|| です。文字列を結合する際に使用します。
算術演算子
+、–、*、/ です。検索条件の値の計算や評価に使用されます。
論理演算子
NOT、AND、OR の 3 つのキーワードがあり、簡単な検索条件で使用し
ます。また、論理演算子を複数使用して、簡単な検索条件をいくつか
組み合わせて複雑な検索条件を作成することもできます。論理演算子
では、通常、結果が TRUE(真)または FALSE(偽)で返されます。
比較演算子
<、>、<=、>=、=、<> で、演算子を挟んで左の値と右の値との比較が
行われます。比較演算子では、結果は TRUE(真)または FALSE(偽)
で返されます。
こ の ほ か、特 殊 な 比 較 演 算 子 と し て、ALL、ANY、BETWEEN、
CONTAINING、
EXISTS、
IN、
IS、
LIKE、
NULL、
SINGULAR、
SOME、
STARTING
結果は TRUE(真)
、FALSE
WITH があります。これらの比較演算子では、
(偽)
、UNKNOWN(不定)のいずれかで返されます。
COLLATE 句
CHAR または VARCHAR の値の比較では、COLLATE 句が必要になるこ
とがあります。この句を使用して、比較の際の文字の照合順序を設定
できます。
第 6 章 データ処理
6-27
SELECT に よ る デ ー タ の 取 り 出 し
表 6.12 WHERE 句の検索条件の要素 ( 続き )
要素
説明
ストアドプロシージャ
再利用可能な SQL 文のブロックです。ストアドプロシージャを使って
パラメータのやりとりが可能になります。ストアドプロシージャは、
データベースのメタデータとして格納されています。クエリーにおけ
るストアドプロシージャの詳細は、第 10 章「ストアドプロシージャ」
を参照してください。
サブクエリー
WHERE 句の中にネストされた SELECT 文を指し、メインの SELECT 文
により検索された行に対して比較を行い、比較による値を返したり、
計算を行ったりします。サブクエリーの詳細は、6-51 ページの「サブ
クエリー」を参照してください。
かっこ
かっこを使用して、式の複数の要素を相互の関連に基づいてグループ
化することができます。かっこで括った場合、その部分が優先的に処
理されるとともに、値が 1 つ生成されます。この値は、かっこを置い
た式の中で使用されます。また、かっこで囲んだ式は、式の中にネス
トすることができます。
簡単な検索条件を複数組み合わせることで、複雑な検索条件を作成することができます。た
とえば、次の WHERE 句は、列名が 2 つ、定数が 3 つ、比較演算子が 3 つ、かっこでグルー
プ化した式が 1 つ、という複雑な構成の検索条件の例です。この WHERE 句では、給与が
60,000 ドルを超えていて 120,000 ドル未満の範囲である社員の行が取り出されます。
WHERE DEPARTMENT = 'Publications' AND
(SALARY > 60000 AND SALARY < 120000)
また、WHERE 句では、検索条件の中に、ネストされた SELECT 文(サブクエリー)を記述
することもあります。たとえば、次は、WHERE 句に集計関数である AVG() を使用している
クエリーの例です。このクエリーでは、給与を部署別で見た場合、その給与が全部署の平
均値より高い部署が取り出されます。
EXEC SQL
DECLARE WELL_PAID CURSOR FOR
SELECT DEPT_NO
INTO :wellpaid
FROM DEPARTMENT
WHERE SALARY > (SELECT AVG(SALARY) FROM DEPARTMENT);
SQL 式を使った検索条件の設定については、6-4 ページの「SQL 式」を参照してください。
サブクエリーを使って検索条件を指定する方法の詳細は、6-51 ページの「サブクエリー」
を参照してください。集計関数の詳細は、6-21 ページの「集合列のデータの取り出し」を
参照してください。
文字列の比較における照合順序
WHERE 句では、CHAR(n) または VARCHAR(n) の値(文字列)を相互に比較する際、双方
の値の照合順序が異なる場合は、照合順序を指定しなければなりません。
比較時に値に使用する照合順序を指定するには、値の後に COLLATE 句を入れます。たとえ
ば、次の埋め込みアプリケーションのコード内の WHERE 句では、比較演算子の左にある
値は、特定の照合順序で強制的に比較されます。
6-28 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
WHERE LNAME COLLATE FR_CA = :lname_search;
InterBase で用意されている照合順序の種類については、
『データ定義ガイド』を参照してく
ださい。
ORDER BY による行のソート
クエリーが実行された場合、デフォルトで、検索で見つかった順番どおりにテーブルの行
が取り出されます。また、InterBase の内部では、テーブルの行は順不同で格納されている
ため、通常は取り出された行も順不同ということになります。InterBase には ORDER BY 句
が用意されており、この句を使ってクエリーで行を取り出すと、同時に順番も整理(ソー
ト)することができます。ORDER BY 句はオプションで、SELECT 文の末尾に記述します。
ORDER BY 句では、必要に応じて列名を指定します。行は、この指定された列を基準にし
てソートされることになります。ここで指定できる列名は、文の先頭部分の SELECT 文で記
述されているものに限られます。各列に対しては、ソート順として昇順(ASC、デフォル
ト)または降順(DESC)を指定できます。ORDER BY の正規の構文は次のとおりです。
ORDER BY col [COLLATE collation] [ASC | DESC]
[,col [COLLATE collation] [ASC | DESC] ...];
たとえば、次のカーソル宣言では、取り出された行は LAST_NAME 列を基準にソートされ
て出力されます。ここでは、ORDER BY 句で降順が指定されているため、姓名が Z で始ま
る社員が最初に、A で始まる社員が最後に、という順番で出力されます。
EXEC SQL
DECLARE PHONE_LIST CURSOR FOR
SELECT LAST_NAME, FIRST_NAME, PHONE_EXT
FROM EMPLOYEE
WHERE PHONE_EXT IS NOT NULL
ORDER BY LAST_NAME DESC, FIRST_NAME;
ORDER BY 句に複数の列を指定する
ORDER BY 句で列名を複数記述した場合、まず行は、最初の列を基準にソートされます。こ
の後、最初の列の値として同じ値を持つ行が複数あった場合、さらに 2 番めに指定した列
を基準に各行がソートされます。3 番め、4 番めの列を指定している場合も、同じ要領で
ソートが行われます。また、列名にはそれぞれ個別にソート順を指定できます。
重要
マルチカラムのソートでは、指定されたソート順は、それ以降、他のソート順が指定され
るまでのすべての列にも適用されます。これは前の例でも示されています。この属性は「ス
ティッキー」ソート順と呼ばれることもあります。前の例では、FIRST_NAME にソート順
が指定されていないので、この列のソート順は昇順になります。FIRST_NAME を降順でソー
トする場合は、次の例のように明示的に DESC の指定を行います。
EXEC SQL
DECLARE PHONE_LIST CURSOR FOR
SELECT LAST_NAME, FIRST_NAME, PHONE_EXT
FROM EMPLOYEE
WHERE PHONE_EXT IS NOT NULL
ORDER BY LAST_NAME DESC, FIRST_NAME ASC;
第 6 章 データ処理
6-29
SELECT に よ る デ ー タ の 取 り 出 し
ORDER BY 句における照合順序
SELECT 文で CHAR 列または VARCAHR 列を順序付ける場合、特に順序付けに使用される
列が異なる照合順序を使用しているときは、順序付けの照合順序を指定する必要がありま
す。
ORDER BY 句で照合順序を指定するには、照合順序を指定する列名の右に COLLATE 句と
照合順序を記述します。これで、指定した照合順序がソートの際に使用されることになり
ます。たとえば、次の ORDER BY 句では、2 つの列に対して、それぞれ別の照合順序を指定
しています。
. . .
ORDER BY LNAME COLLATE FR_CA, FNAME COLLATE FR_FR;
InterBase で用意されている照合順序の種類については、
『データ定義ガイド』を参照してく
ださい。
GROUP BY による複数行のグループ化
オプションの GROUP BY 句を使用して、列の値が同じ行を一括してグループ化すると同時に、
なんらかの集計値を出力することができます。したがって、GROUP BY では、検索条件に該
当する行が逐次取り出されることはありません。GROUP BY の正規の構文は次のとおりです。
GROUP BY col [COLLATE collation] [, col [COLLATE collation] ...]
たとえば、ここで、カーソル宣言を 2 つ考えてみます。1 つは、テーブルから社員全員の部
署と姓名を取り出し、部署と姓名を基準に各行を昇順でソートします。記述は次のように
なります。
EXEC SQL
DECLARE DEPT_EMP CURSOR FOR
SELECT DEPARTMENT, LAST_NAME, FIRST_NAME
FROM DEPARTMENT D, EMPLOYEE E
WHERE D.DEPT_NO = E.DEPT_NO
ORDER BY DEPARTMENT, LAST_NAME, FIRST_NAME;
もう 1 つは、集計関数と GROUP BY を使用して、集計値を出力するカーソル宣言です。こ
の処理は、グループ集合と呼ばれています。このクエリーでは、部署別の社員の平均給与が
返されます。つまり、GROUP BY 句により、DEPARTMENT 列(部署)の値が同じ行が全部
取り出された後、各部署について平均値が計算されます。また、ORDER BY 句も記述され
ているため、行(部署と平均給与)が部署名を基準にアルファベット順にソートされます。
EXEC SQL
DECLARE AVG_DEPT_SAL CURSOR FOR
SELECT DEPARTMENT, AVG(SALARY)
FROM DEPARTMENT D, EMPLOYEE E
WHERE D.DEPT_NO = E.DEPT_NO
GROUP BY DEPARTMENT
ORDER BY DEPARTMENT;
6-30 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
GROUP BY 句での照合順序
SELECT 文で CHAR 列または VARCAHR 列をグループ分けする場合、特に、グループ分け
に使用される列が異なる照合順序を使用しているならば、グループ分けの照合順序を指定
する必要があります。
GROUP BY 句 で 列 の グ ル ープ分けに使用する照合順序を指定するには、列名の後に
COLLATE 句を入れます。たとえば、次の GROUP BY 句では、2 つの列の照合順序が指定さ
れています。
. . .
GROUP BY LNAME COLLATE FR_CA, FNAME COLLATE FR_CA;
InterBase で用意されている照合順序の種類については、
『データ定義ガイド』を参照してく
ださい。
GROUP BY を使用する場合の注意
GROUP BY を使用する場合、次の点に注意が必要です。
• GROUP BY 句で指定できる列名は、SELECT 句で指定されているものに限られます。
• GROUP BY 句では、算術関数や集計関数、ユーザー定義関数によって値が返されるような
列は指定できません。
• GROUP BY は、次のような SELECT 文では使用できません。
• INTO 句が記述されている場合(単一行 SELECT)
• サブクエリーが記述され、その FROM 句でビューが指定されており、かつ GROUP
BY 句または HAVING 句が記述されている場合
• クエリー(サブクエリーを含む)では、GROUP BY 句は、SELECT 句 1 つにつき 1 つしか
使用できません。
HAVING による複数行のグループ化
SELECT 句では、WHERE 句を使って取り出す行の数を絞り込むことができます。同じよう
に、HAVING 句を使用して、GROUP BY 句で取り出された行の数を限定することができま
す。HAVING の構文は次のとおりです。
HAVING <search_condition>
HAVING では検索条件を記述でき、記述方法は WHERE 句の場合とほぼ同じです。ただし、
次のような制限があります。
• HAVING 句の検索条件は、
通常、
SELECT 句で指定されている集計関数を基本に記述します。
• HAVING 句でサブクエリーを記述する場合、その FROM 句では、メインのクエリーですで
に指定されているテーブルまたはビューの名前は指定できません。
• HAVING 句では、相関的なサブクエリーは記述できません。
たとえば、次は、会社の部署別に社員の平均給与を計算するカーソル宣言です。ここでは、
GROUP BY 句により、部署別の平均給与が計算されます。また、HAVING 句で、部署の平
均給与のうち 60000 を超えるものだけが取り出され、続いて、ORDER BY 句により、行(部
署と平均給与)が部署名を基準にアルファベット順にソートされて出力されます。
EXEC SQL
第 6 章 データ処理
6-31
SELECT に よ る デ ー タ の 取 り 出 し
DECLARE SIXTY_THOU CURSOR FOR
SELECT DEPARTMENT, AVG(SALARY)
FROM DEPARTMENT D, EMPLOYEE E
WHERE D.DEPT_NO = E.DEPT_NO
GROUP BY DEPARTMENT
HAVING AVG(SALARY) > 60000
ORDER BY DEPARTMENT;
メモ
HAVING は、必ずしも GROUP BY と併用する必要はありません。HAVING を GROUP BY
なしで使った場合、SELECT により取り出された行はグループ化されません。したがって、
SELECT 句で列に対して集計関数を使用している場合、全行が計算の対象となります。
検索条件の詳細は、6-26 ページの「WHERE での行の絞り込み」を参照してください。サ
ブクエリーの詳細は、6-51 ページの「サブクエリー」を参照してください。
ROWS による結果セットの限定
ROWS 句を使用すると、行数、行の範囲、または行の割合を指定して、結果セットの一部
を取り出すことができます。また、n 行ごとに結果を取得したり、WITH TIES キーワードを
使って重複行を取得することもできます。ROWS は、ORDER BY 句と組み合わされて最も
よく使用されます。
ROWS 句の構文は次のとおりです。
ROWS <value> [TO <upper_value>] [BY <step_value>][PERCENT][WITH TIES]
ROWS 句は、テーブル式の結果セットから、一部の行だけを取り出します。この機能は、結
果を連続したチャンクで返す必要がある場合に便利です。たとえば、Web 開発者が Web
サーバーからクライアントのブラウザに大きな結果セットを小分けして送信する必要があ
る場合に使用できます。このような Web アプリケーションは、データベースサーバーとス
テートレスにやりとりするため、カーソルを使って結果セット全体を少しずつスクロール
したり、結果セット全体をクライアントのデータセットキャッシュにダウンロードするこ
とはできません。そのかわり、ROWS 句を使用して、結果セット全体から返される行の番
号を指定しながら、同じ SQL クエリーをデータベースサーバーに繰り返し送信します。
ROWS 句にはいくつかのオプションの要素があり、さまざまな結果を生成できます。表
6.13 にそれらのオプションを示します。
表 6.13 ROWS 句の形式
式
返される情報
ROWS n
結果セットの最初の n 行を返す。PERCENT とともに使用する場合は、n
パーセントを返す。
TOWS m TO n
m ~ n 行め
(両端を含む)を返す。または、m ~ n パーセントの行を返す。
ROWS n BY p
最初の n 行内の p 行ごとの行を返す。
6-32 埋 め 込 み S Q L ガ イ ド
SELECT に よ る デ ー タ の 取 り 出 し
表 6.13 ROWS 句の形式 ( 続き )
式
返される情報
ROWS m TO n BY p
m ~ n 行め内の p 行ごとの行を返す。
ROWS n PERCENT
• 結果セットの最初の n パーセントを返す。
• この例の「ROWS n」の部分には、任意の正しい「ROWS」構文を
置くことができる。PERCENT は、ROWS で指定されたすべての値
に適用される。
ORDER BY …
ROWS n WITH TIES
• WITH TIES は、並べ替えられたシーケンス内の最後の値が結果セッ
トの後続の行内の値と同じ場合に、余分な重複行を返す。ORDER
BY と組み合わせて使用する必要がある。
• 行数を指定した場合、TIES で返される重複行は、単一行としてカ
ウントされる。
• この例の「ROWS n」部分には、任意の正しい「ROWS」構文を置
くことができる。
UNION によるテーブルの付加
場合によっては、データベース中に、構造が同じか、または列のデータが類似しているテー
ブルが複数収められていることがあります。このように、同じような構造を持ったテーブル
が複数ある場合は、各テーブルを結合して 1 つの結果テーブルを作成することができます。
この結果テーブルは、各テーブルの有効行をもとに作成された射影と呼ぶことができます。
テーブルの結合には UNION 句を使用します。この UNION 句により、各テーブルの全行が
まとめて取り出され、相互に結合されます。なお、重複データがあった場合には自動的に
排除され、1 つだけに絞られます。
テーブルの UNION は、データを集合する場合によく使用されます。
UNION の構文は次のとおりです。
UNION SELECT col [, col ...]| * FROM <tableref> [, <tableref> ...]
たとえば、CITIES、COUNTRIES、NATIONAL_PARKS という 3 つのテーブルに、いずれも
都市名が格納されていたとします。また、トリガーは設定されておらず、したがって別の
テーブルに対して同じデータの自動入力は行われていないものとします。この場合、次の
ように UNION を使用して、3 つのテーブルの都市名をすべて 1 つのテーブルにまとめるこ
とができます。
EXEC SQL
DECLARE ALLCITIES CURSOR FOR
SELECT CIT.CITY FROM CITIES CIT
UNION SELECT COU.CAPITAL FROM COUNTRIES COU
UNION SELECT N.PARKCITY FROM NATIONAL_PARKS N;
ヒント
場合によっては、結合するテーブルがまったく同じ構造、つまり、列の数や名前、データ
型が同じで、各列の値も類似していることがあります。このような場合、UNION の SELECT
句で列を指定するかわりにアスタリスク(*)を記述します。これで、列が全部指定されます。
第 6 章 データ処理
6-33
SELECT に よ る デ ー タ の 取 り 出 し
PLAN によるクエリープランの指定
InterBase では、SELECT 文は、クエリー最適化機能(query optimizer)と呼ばれる内部アル
ゴリズムによって処理されます。この場合、クエリー最適化機能により、データの取り出
しに最も効果的な方法が自動的に採用されます。したがって、このクエリー最適化機能にク
エリーの方法を任せることで、最高速のデータ取り出しが可能になります。しかし、場合に
よっては、効率の悪い方法が選択されることもあります。たとえば、データベースの使用状
況によっては、テーブルの行数がかなり多くなることもあります。また、テーブルのイン
デックス付きの列にいくつも重複行が挿入されたり、多数の重複行が削除されたりして、イ
ンデックスの選択能力が低下するといったことも起こります。このような場合、最適化機
能により効率の低いクエリーの方法が選択されてしまいます。
このような場合は、オプションの PLAN 句を使用して、データ取り出しのための独自のク
エリーの方法を指定できます。このクエリーの方法をクエリープランと呼びます。PLAN で
は、主にインデックス関連の操作を行いクエリープランを作成します。つまり、使用するイ
ンデックスの指定、複数のインデックスの結合、アクセス方法の指定といった作業を行っ
て、クエリープランを構築することになります。
クエリープランを指定するための PLAN の構文は次のようになります。
PLAN <plan_expr>
<plan_expr> =
[JOIN | [SORT] MERGE] (<plan_item> | <plan_expr>
[, <plan_item> | <plan_expr> ...])
<plan_item> = {table | alias}
NATURAL | INDEX ( <index> [, <index> ...]) | ORDER <index>
PLAN 構文では、1 つのテーブルを指定できるほか、複数のテーブルを結合することもでき
ます。また、かっこを使って式(<plan_expr>)をネストし、複雑な式を記述することもで
きます。
PLAN で複数のテーブルを結合した場合、取り出しの際は各テーブルのデータが結合され
るため、処理が高速化されます。また、インデックスを指定したときは、そのインデックス
を使って結合が行われます。テーブルを結合する場合、JOIN キーワードを使用します。結
合するテーブルのデータにインデックスが設定されていないときは、JOIN のかわりに
SORT MERGE を指定して取り出し処理を高速化できます。
plan_item は、検索対象のデータが格納されているテーブル名を表します。クエリーで、同じ
テーブルを複数回使用する場合は、PLAN 句ではエイリアスを使ってテーブルを指定しな
ければなりません。また、plan_item では、行に対するアクセス方法を指定します。指定でき
るアクセス方法と処理内容は、次の 3 種類です。
• NATURAL:テーブルの行に対して順次アクセスが行われます。デフォルトのアクセス方法
で、インデックスが付けられていない場合、この方法以外では指定できません。
• INDEX:指定したインデックスを介して行へのアクセスが行われます。使用するインデッ
クスは、INDEX の右にすべて列挙しておかなければなりません。なお、INDEX にテーブル
のインデックスが全部指定され、その PLAN 句の後に論理演算子または連結演算子による
処理が記述されているときは、その処理ではインデックスは一切使用されません。また、
INDEX で指定したインデックスが使用不能のときは、エラーが報告されます。
• ORDER:インデックスの名前を併記しておくと、そのインデックスに設定されているソー
ト順にしたがって行がソートされます。
6-34 埋 め 込 み S Q L ガ イ ド
1 行の取り出し
1 行の取り出し
テーブルから 1 行または行の一部を取り出す処理を単一行 SELECT(singleton select)と呼び
ます。単一行 SELECT では、SELECT 文は次のようになります。この構文は、ユニークイン
デックスが設定されている列のデータを取り出す場合、また、COUNT() や AVG() を使って
集合値を取り出す場合も同じです。
SELECT <col> [, <col> ...]
INTO :variable [, :variable ...]
FROM table
WHERE <search_condition>;
上の文で、INTO 句は必須で、ここには変数を指定します。取り出されたデータはこの変数
に格納され、プログラムで使用されることになります。変数の名前の前にはコロン(:)を
付けなければなりません。変数は、データを取り出す列(SELECT 句で指定した列)の数だ
け必要です。また、データは、SELECT 句で指定した列の順番で取り出されるため、INTO
の変数も同じ順番で記述する必要があります。
単一行 SELECT の場合、WHERE 句では、1 行が取り出されるように検索条件を記述しなけ
ればなりません。検索条件で取り出される行が複数のときは、その SELECT 句による処理は
実行されません。
重要
ユーザーがテーブルからデータを取り出すには、そのユーザーに、データが格納されてい
るテーブルの SELECT 特権が与えられていることが条件となります。また、ユーザーがス
トアドプロシージャを使用する場合、そのストアドプロシージャに、データを取り出すテー
ブルの SELECT 特権が与えられていることが必要です。
次の例の SELECT は、DEPARTMENT テーブルから Publications 部の情報を取り出します。
EXEC SQL
SELECT DEPARTMENT, DEPT_NO, HEAD_DEPT, BUDGET, LOCATION, PHONE_NO
INTO :deptname, :dept_no, :manager, :budget, :location, :phone
FROM DEPARTMENT
WHERE DEPARTMENT = 'Publications';
上記のクエリーでは、取り出された行のうち、DEPARTMENT 列のデータが変数 deptname
に、DEPT_NO 列のデータが変数 dept_no に、HEAD_DEPT 列のデータが変数 manager に、順
に格納されます。
複数行の取り出し
一般にほとんどのクエリーでは、複数行を取り出すための検索条件を指定します。たとえ
ば、給与が 60000 ドルを超える社員をすべて取り出すといったクエリーがあります。
変数には 1 つのデータしか格納できないことから、複数行を取り出すクエリーではメモリ
上に一時的なテーブルが作成され、このテーブルに行が格納されます。このテーブルを結
果テーブルと呼びます。結果テーブルに格納された行は、その後一括して、格納された順
第 6 章 データ処理
6-35
複数行の取り出し
番で抽出および処理が行われることになります。なお、SQL では、次に処理する結果テーブ
ル上の行に対して自動的にポインタが作成され、このポインタにより行の管理が行われま
す。このポインタはカーソルと呼ばれます。
重要
DSQL では、複数行を取り出す場合のクエリーの記述方法が SQL とは多少異なります。
DSQL における複数行の選択の詳細は、6-43 ページの「DSQL での複数行の取り出し」を
参照してください。
上記のように、複数行を取り出すクエリーでは、行は結果テーブルに暫定的に格納され、
カーソルにより行が処理されることになります。したがって、この種のクエリーでは、次
のような文を順に記述しなければなりません。
1
2
3
DECLARE CURSOR:カーソル名を宣言し、実行するクエリーを指定します。
OPEN:クエリーを実行します。結果テーブルが作成され、カーソルがテーブルの先頭
に配置されます。
FETCH:この FETCH により、結果テーブルの行が 1 行ずつ取り出され、変数に格納さ
れます。
4
CLOSE:すべての行が取り出されたら、CLOSE によってシステムリソースが解放され
ます。
重要
ユーザーによるデータの取り出しでは、そのユーザーに、データが格納されているテーブ
ルの SELECT 特権が与えられていることが条件となります。また、ユーザーがストアドプ
ロシージャを使用する場合、そのストアドプロシージャに、データを取り出すテーブルの
SELECT 特権が与えられていることが必要です。
カーソルの宣言
DECLARE CURSOR 文では、カーソルの宣言を行います。また、SELECT 句を使用して、最
終的に取り出す行を指定します。
なお、DECLARE CURSOR は情報文で、クエリーの実行とは無関係です。つまり、DECLARE
CURSOR に記述された情報に基づいてシステムリソースの準備が行われ、後続の OPEN で
カーソルが開かれると、そのシステムリソースが割り当てられます。このように、DECLARE
CURSOR はクエリーの実行とは直接関係ないため、SQLCODE が割り当てられることはあ
りません。
DECLARE CURSOR の構文は次のとおりです。
DECLARE cursorname CURSOR FOR
SELECT <col> [, <col> ...]
FROM table [, <table> ...]
WHERE <search_condition>
[GROUP BY col [, col ...]]
[HAVING <search_condition>]
[ORDER BY col [ASC | DESC] [, col ...] [ASC | DESC]
| FOR UPDATE OF col [, col ...]];
上の例で、cursorname はカーソル名です。この名前は、後続の OPEN、FETCH、CLOSE の
各文で有効なカーソルを指定するときに使用できます。
6-36 埋 め 込 み S Q L ガ イ ド
複数行の取り出し
次の例を除いて、DECLARE CURSOR 内の SELECT 文の記述方法は、DECLARE CURSOR が
ない場合の SELECT と同じです。
• DECLARE CURSOR 中の SELECT では、INTO 句は記述できません。
• DECLARE CURSOR 中の SELECT では、ORDER BY 句と FOR UPDATE 句のどちらか 1 つ
しか記述できません。
次は、DECLARE CURSOR によるカーソル宣言の例です。
EXEC SQL
DECLARE TO_BE_HIRED CURSOR FOR
SELECT D.DEPARTMENT, D.LOCATION, P.DEPARTMENT
FROM DEPARTMENT D, DEPARTMENT P
WHERE D.MNGR_NO IS NULL
AND D.HEAD_DEPT = P.DEPT_NO;
カーソルを使った更新
ア プ リケ ー シ ョ ン で は、通常、データの取り出しの後に更新を行います。この場合、
DECLARE CURSOR でオプションの FOR UPDATE 句を記述することで、取り出したデータ
を更新可能な状態にしておくことができます。FOR UPDATE の右に列名を指定すると、こ
の列のデータが更新可能な状態になります。次は、FOR UPDATE 句を記述したカーソル宣
言の例です。
EXEC SQL
DECLARE H CURSOR FOR
SELECT CUST_NO
FROM CUSTOMER
WHERE ON_HOLD = '*'
FOR UPDATE OF ON_HOLD;
FOR UPDATE 句は記述を省略することも可能で、この場合、取り出された行の列(SELECT
で指定した列)すべてが更新可能になります。たとえば、次のクエリーでは、2 つの列の
データが両方とも更新可能になります。
EXEC SQL
DECLARE H CURSOR FOR
SELECT CUST_NAME CUST_NO
FROM CUSTOMER
WHERE ON_HOLD = '*';
カーソルによる列の更新の詳細は、6-61 ページの「複数行の更新」を参照してください。
カーソルのオープン
カーソル宣言の後、OPEN 文を使ってカーソルを開くと、データの取り出しが可能になり
ます。OPEN では、カーソルが起動すると同時に結果テーブルが作成されます。この場合、
結果テーブルは、DECLARE CURSOR 文で指定されている検索条件をもとに作成されます。
なお、結果テーブルに格納されている行をまとめて、カーソルのアクティブセットと呼ん
でいます。
第 6 章 データ処理
6-37
複数行の取り出し
次の文は、DECLARE CURSOR で宣言済みの DEPT_EMP というカーソルを開く場合の記述
です。
EXEC SQL
OPEN DEPT_EMP;
OPEN 文でカーソルを開くと、カーソルは結果テーブルの最初の行の先頭に置かれます。
カーソルによる行の取り出し
カーソルを開くと、行の取り出しが可能な状態になります。行の取り出しには FETCH 文を
使用します。FETCH では、行が結果テーブルから一度に 1 行ずつ取り出されます。FETCH
の処理の順序は、次のようになります。
1
2
3
結果テーブルの最初の有効行が取り出されます。
取り出された行が、FETCH 文の INTO 句に記述された変数に格納されます。
結果テーブルの次の有効行の先頭にカーソルが置かれます。なお、カーソルがテーブル
の末尾に移動し、その後には取り出し対象の行がない場合は、SQLCODE に 100 が入れ
られます。
FETCH 文の正規の構文は次のとおりです。
FETCH <cursorname> INTO :variable [[INDICATOR] :variable]
[, :variable [[INDICATOR] :variable>] ...];
重要
FETCH は、DSQL で複数行の取り出しを行う場合にも使用できますが、使い方が異なりま
す。DSQL での複数行の取り出しの詳細は、6-45 ページの「DSQL カーソルによる複数行
の取り出し」を参照してください。
たとえば、次の文は、DEPT_EMP というカーソルを使って結果テーブルの行を取り出し、
列のデータをそれぞれ deptname、lname、fname という変数に格納する例です。
EXEC SQL
FETCH DEPT_EMP
INTO :deptname, :lname, :fname;
上記と同じ要領で、結果テーブルの行全部を順に取り出すこともできます。この場合、
FETCH 文をホスト言語の繰り返し文の中に記述します。たとえば、次の C のコードでは、
DEPT_EMP カーソルによって取り出される行がすべて表示されます。
. . .
EXEC SQL
FETCH DEPT_EMP
INTO :deptname, :lname, :fname;
while (!SQLCODE)
{
printf("%s %s works in the %s department.¥n", fname,
lname, deptname);
EXEC SQL
FETCH DEPT_EMP
INTO :deptname, :lname, :fname;
6-38 埋 め 込 み S Q L ガ イ ド
複数行の取り出し
}
EXEC SQL
CLOSE DEPT_EMP;
. . .
FETCH 文ではいずれも、アクティブセット(結果テーブルの各行)が終了したかどうかを
判定しなければなりません。たとえば、上の例では SQLCODE を使用しています。この
SQLCODE が 0 の間は while ループの処理が続きます。一方、結果テーブルで取り出す行が
なくなった時点で SQLCODE に 100 が設定され、while ループの処理が終了します。なお、
SQLCODE の値がマイナスのときは、なんらかのエラーが発生したことを示します。
INDICATOR によるインジケータ変数の設定
列に NOT NULL または UNIQUE の整合性制約が設定されている場合は別ですが、テーブ
ルの列によっては値が NULL のことがあります。この NULL は、列の値が未入力の場
合、InterBase によりフラグとして自動的に設定された値です(列の属性が NULL に設定され
ている場合)。
列の値が NULL であるかどうかは、INDICATOR キーワードを使って確認できます。この
INDICATOR は、INTO 句に指定した変数の右に記述します。また、INDICATOR の右には
16 ビット整数の変数を指定します。この 16 ビット整数の変数をインジケータ変数(indicator
variable)と呼び、取り出された値に応じて、フラグの状況(NULL であるかどうか)を示
す値がインジケータ変数に設定されます。インジケータ変数に設定される値は次の 2 種類
です。
• 取り出された値が NULL の場合、インジケータ変数は –1 に設定されます。
• 取り出された値が NULL 以外の場合、インジケータ変数は 0 に設定されます。
たとえば、次の C コードは、department、manager、missing_manager という 3 つの変数を宣
言し、2 つの列の値を department と manager の 2 つの変数に格納する例です。ここでは、変
数 manager に INDICATOR が設定されているので、変数 manager に対応する列の値に応じ
て、インジケータ変数 missing_manager にフラグが設定されます。FETCH 文の GETCITY は、
宣言済みのカーソルの名前です。
. . .
char department[26];
char manager[36];
short missing_manager;
. . .
FETCH GETCITY INTO :department, :manager INDICATOR :missing_manager;
なお、INDICATOR キーワードは省略することもできます。次は、省略した例です。
FETCH GETCITY INTO :department, :manager :missing_manager;
さらに、列の値が格納される変数と NULL 値のフラグを含むインジケータ変数の間のス
ペースも省略できます。その場合、記述は次のようになります。
FETCH GETCITY INTO :department, :manager:missing_manager;
第 6 章 データ処理
6-39
複数行の取り出し
メモ
InterBase では、FETCH で記述した変数の数と DECLARE CURSOR の SELECT で記述した列
の数は一致しなければなりませんが、FETCH 文のインジケータ変数は例外でカウントされ
ません。
カーソルによる行の再取り出し
FETCH による処理では、カーソルはアクティブセットの最初から最後まで一度しか移動し
ません。
したがって、同じ結果テーブルの行をもう一度取り出すときは、いったんカーソルを閉じ
て、OPEN 文を使ってカーソルを再度開かなければなりません。たとえば、DEPT_EMP カー
ソルをいったん閉じて、再度開く場合、次のようになります。これで、同じ結果テーブル
の先頭にカーソルが再設定されます。
EXEC SQL
CLOSE DEPT_EMP;
EXEC SQL
OPEN DEPT_EMP;
カーソルのクローズ
カーソルがアクティブセットの最後に移動したら、そのカーソルを閉じなければなりませ
ん。その結果、システムリソースが解放されます。カーソルを閉じるには CLOSE 文を使用
します。次の文は、DEPT_EMP カーソルを閉じる場合の記述例です。
EXEC SQL
CLOSE DEPT_EMP;
なお、カーソルがアクティブセットの最後まで達したかどうかは、SQLCODE を使って検証
します。SQLCODE の値が 100 に設定された場合、取り出す行が存在しないと判定されます。
カーソルによる行の取り出しのプログラム例
次は、カーソルを宣言して開いた後、ループ処理によってアクティブセットでカーソルを
移動し、FETCH による値の取り出しと表示の各処理をまとめたプログラム例です。このプ
ログラムでは、処理がすべて終了するとカーソルが閉じます。また、エラーが発生したと
きもカーソルが閉じるように記述してあります。
#include <stdio.h>
EXEC SQL
BEGIN DECLARE SECTION;
char deptname[26];
char lname[16];
char fname[11];
EXEC SQL
END DECLARE SECTION;
main ()
{
6-40 埋 め 込 み S Q L ガ イ ド
複数行の取り出し
EXEC SQL
WHENEVER SQLERROR GO TO abend;
EXEC SQL
DECLARE DEPT_EMP CURSOR FOR
SELECT DEPARTMENT, LAST_NAME, FIRST_NAME
FROM DEPARTMENT D, EMPLOYEE E
WHERE D.DEPT_NO = E.DEPT_NO
ORDER BY DEPARTMENT, LAST_NAME, FIRST_NAME;
EXEC SQL
OPEN DEPT_EMP;
EXEC SQL
FETCH DEPT_EMP
INTO :deptname, :lname, :fname;
while (!SQLCODE)
{
printf("%s %s works in the %s department.¥n",fname,
lname, deptname);
EXEC SQL
FETCH DEPT_EMP
INTO :deptname, :lname, :fname;
}
EXEC SQL
CLOSE DEPT_EMP;
exit();
abend:
if (SQLCODE)
{
isc_print_sqlerror();
EXEC SQL
ROLLBACK;
EXEC SQL
CLOSE_DEPT_EMP;
EXEC SQL
DISCONNECT ALL;
exit(1)
}
else
{
EXEC SQL
COMMIT;
EXEC SQL
DISCONNECT ALL;
exit()
}
}
第 6 章 データ処理
6-41
複数行の取り出し
NULL 値が格納されている行の取り出し
列に NOT NULL または UNIQUE の整合性制約が設定されている場合は別ですが、テーブ
ルの列によっては値が NULL のことがあります。この NULL は、列の値が未入力の場
合、InterBase によりフラグとして自動的に設定された値です(列の属性が NULL に設定され
ている場合)。
列の値として NULL が格納されている行は、WHERE 句に IS NULL を記述して検索できま
す。たとえば、DEPARTMENT というテーブルの行のうち、BUDGET という列に値が入力さ
れていない行がいくつかあったとします。
つまり、会社の各部署を記録したテーブルで、まだ予算を入力していない部署があり、そ
の部署の予算の列(BUDGET)の値が NULL ということになります。この場合、次のカー
ソル宣言を使用して、予算の入力が終わっていない部署を取り出すことができます。また、
FOR UPDATE を使って更新の準備も行っています。
EXEC SQL
DECLARE NO_BUDGET CURSOR FOR
SELECT DEPARTMENT, BUDGET
FROM DEPARTMENT
WHERE BUDGET IS NULL
FOR UPDATE OF BUDGET;
メモ
列に NULL 値が入っているかどうかは、インジケータ変数を使って検証できます。インジ
ケータ変数の詳細は、6-39 ページの「INDICATOR によるインジケータ変数の設定」を
参照してください。
直接クエリーでは、列の値が NULL の場合、その列のデータが数値のときには 0 が返され
ます。また、文字のときは空白が、日付のときには "17 November 1858" が返されます。たと
えば、次のカーソル宣言では、各部署の予算がすべて取り出されますが、そのうち NULL
値を持つ行については 0 が返されます。
EXEC SQL
DECLARE ALL_BUDGETS CURSOR FOR
SELECT DEPARTMENT, BUDGET
FROM DEPARTMENT
ORDER BY BUDGET DESCENDING;
NULL 値を扱う場合の注意
InterBase では、NULL は値のない値として認識されます。このため、NULL 値を扱うとき
は、次のような点に注意が必要です。
• NULL 値が格納された列を含む行のソートは、他の行のソート後に実行されます。
• 集合処理では、NULL 値は計算の対象から除外されます。ただし、COUNT(*) では集合の対
象となります。
• 否定処理を行う検索条件では、NULL 値は取り出されません。
• 結合の検索条件では、列の値として NULL が格納されている行は取り出されません。
NULL 値は、比較演算子を使って他の値と比較することができます。この場合、比較演算子
のどちらか一方の値が NULL のときは、UNKNOWN(不定)が返されます。
6-42 埋 め 込 み S Q L ガ イ ド
DSQL での複数行の取り出し
また、論理演算子(NOT、AND、OR)による比較では、戻り値は次のようになります。
• NOT では、左側と右側の検索条件の戻り値にかかわりなく、必ず UNKNOWN(不定)が
返されます。
• AND では、どちらかの検索条件のオペランドが FALSE(偽)以外のときは、UNKNOWN
(不定)が返されます。どちらかのオペランドが FALSE(偽)の場合は、FALSE(偽)が返
されます。
• OR では、どちらかの検索条件のオペランドが TRUE(真)以外のときは、UNKNOWN(不
定)が返されます。どちらかのオペランドが TRUE(真)のときは、TRUE(真)が返されます。
入力がない場合の値として、NULL 以外の値をデフォルトとすることもできます。NULL 以
外の値の定義については、『データ定義ガイド』を参照してください。
ビューによる行の取り出し
テーブルのかわりにビューを使って行の一部を取り出すときは、SELECT の FROM 句に
テ ー ブ ル で は な く ビ ュ ー の 名 前 を 記 述 し ま す。た と え ば、次 の カ ー ソ ル 宣 言 で
は、PHONE_VIEW というビューをもとに社員の電話番号のリストが出力されます。
EXEC SQL
DECLARE PHONE_LIST CURSOR FOR
SELECT FIRST_NAME, LAST_NAME, PHONE_EXT
FROM PHONE_VIEW
WHERE EMPLOYEE.DEPT_NO = DEPARTMENT.DEPT_NO;
ビューを使って行を取り出す場合、そのビューは複数のテーブルをもとに作成されたもの
(CREATE VIEW で作成)でもかまいません。また、JOIN キーワードを使用して、テーブル
のかわりに複数のビューを結合することもできます。ビューの結合の詳細は、6-45 ページ
の「テーブルの結合」を参照してください。
DSQL での複数行の取り出し
DSQL では、実行時にユーザーがクエリーを入力することができます。このユーザーからの
クエリーをプログラム側で受け取るには、拡張 SQL デスクリプタエリア(XSQLDA)を使
用しなければなりません。クエリーの入出力は、XSQLDA を介して扱われることになりま
す。多少形は異なりますが、DSQL でも DECLARE CURSOR や OPEN、FETCH の各文を利
用できます。複数行を取り出すクエリーに対しては、XSQLDA と関連させながら、このよ
うな文で処理を行うことになります。
DSQL でも、SQL と同様に、取り出した行を結果テーブルに順に格納し、カーソルを所定
の場所に置いて各行を処理するといった手順が必要です。DSQL では、次の手順でこのよう
な処理を行います(カーソル宣言は省略)。
1
2
3
PREPARE:XSQLDA 構造体を用意します。ここには、クエリーの結果が保持されます。
DECLARE CURSOR:カーソル名を宣言し、実行するクエリーを指定します。
OPEN:クエリーを実行します。結果テーブルが作成され、カーソルがテーブルの先頭
に配置されます。
第 6 章 データ処理
6-43
DSQL での複数行の取り出し
4
FETCH:テーブルから一度に 1 行ずつ取り出します。取り出された行は、後続のプロ
グラムで使用されます。
5
CLOSE:すべての行が取り出されたら、CLOSE によってシステムリソースが解放され
ます。
DSQL カーソルの宣言方法、DSQL カーソルを開く方法、および DSQL カーソルによる行の
取り出し方法については、以降のトピックで説明します。XSQLDA 構造体の作成とデータ
入力、および PREPARE による DAQL クエリーの準備の詳細は、第 13 章「動的 SQL」を
参照してください。カーソルを閉じる方法の詳細は、6-40 ページの「カーソルのクローズ」
を参照してください。
DSQL カーソルの宣言
DSQL では、ユーザーが入力した SELECT 文をもとにカーソル宣言が行われます。処理の手
順は次のようになります。
• ユーザーにクエリー(SELECT 文)の入力を求めます。
• ユーザーが入力したクエリーを変数に格納します。
• PREPARE 文を使用して、変数をもとに、クエリーと結果保持用の XSQLDA を用意します。
• クエリーのエイリアスと関連付けて、カーソルを宣言します。
DSQL では、DECLARE CURSOR の正規の構文は次のようになります。
DECLARE cursorname CURSOR FOR queryname;
次は、DSQL のカーソル宣言の C のコード例です。まず、ユーザーの入力したクエリーを
保持するための文字列変数として querystring を宣言した後、gets でユーザーのクエリーを
querystring に格納しています。続いて、querystring をもとに PREPARE で QUERY という名
前のクエリーを用意し、最後に、C というカーソルを宣言しています。このカーソル C は、
クエリーの QUERY と関連付けています。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char querystring [512];
XSQLDA *InputSqlda, *OutputSqlda;
EXEC SQL
END DECLARE SECTION;
. . .
printf("Enter query:"); /* ユーザーにクエリーの入力を求めます */
gets(querystring); /* 文字列を取得し、querystring に格納します */
. . .
EXEC SQL
PREPARE QUERY INTO OutputSqlda FROM :querystring;
. . .
EXEC SQL
DECLARE C CURSOR FOR QUERY;
6-44 埋 め 込 み S Q L ガ イ ド
テーブルの結合
XSQLDA 構造体の作成とデータ入力、および PREPARE による DSQL クエリーの準備の詳
細は、第 13 章「動的 SQL」を参照してください。
DSQL カーソルのオープン
カーソル宣言後、OPEN 文を使ってカーソルを開きます。セクション宣言で宣言済みの入力
用 XSQLDA の情報をもとに結果テーブルが作成され、データの取り出しが可能になりま
す。DSQL の OPEN の構文は、次のとおりです。
OPEN cursorname USING DESCRIPTOR sqldaname;
たとえば、C というカーソルを InputSqlda という XSQLDA を使って開く場合、次のように
なります。
EXEC SQL
OPEN C USING DESCRIPTOR InputSqlda;
DSQL カーソルによる複数行の取り出し
結果テーブルから行を取り出すには FETCH 文を使用します。FETCH によって、宣言済みの
出力用 XSQLDA(拡張 SQL デスクリプタエリア)の情報をもとに行が取り出されます。
DSQL の FETCH の構文は、次のとおりです。
FETCH cursorname USING DESCRIPTOR descriptorname;
たとえば、入力用と出力用の 2 つの XSQLDA 構造体を宣言し、出力用の XSQLDA 構造体を
使って FETCH 文で行を取り出す場合、C のコードは次のようになります。
. . .
XSQLDA *InputSqlda, *OutputSqlda;
. . .
EXEC SQL
FETCH C USING DESCRIPTOR OutputSqlda;
. . .
XSQLDA 構造体の作成とデータ入力、および PREPARE による DSQL クエリーの準備の詳
細は、第 13 章「動的 SQL」を参照してください。
テーブルの結合
結合(join)とは、1 つの SELECT 句を使用して、2 つ以上のテーブルからデータを取り出
す処理を言います。データの取り出し元となるテーブルは、JOIN キーワードを使って
FROM 句に指定します。FROM 句では、オプションで検索条件を記述し、取り出す行を限定
することもできます。さらに、WHERE 句で検索条件を使用して、行を絞り込むことができ
ます。
SELECT 句に JOIN を記述した場合、その SELECT 句の情報に基づいてテーブルが作成され
ます。このテーブルを結果テーブルと呼び、ここには、結合処理での結果が格納されます。
このテーブルを、動的テーブルまたは仮想テーブルと呼ぶこともあります。
第 6 章 データ処理
6-45
テーブルの結合
InterBase は、次の 2 種類の結合をサポートしています。
• 内部結合(inner join)は、結合の検索条件(ON 句の検索条件)にしたがって各テーブルの
行を比較し、行のうち結合の検索条件に適合するものだけを取り出します。内部結合は、さ
らに次の 3 種類に分かれます。
• 同等結合(equi-join)は、各テーブルの列に共通する値、つまり等式を使って列の
値を比較し、行を取り出します。
• 比較結合(comparative join)または非同等結合(non-equi-join)は、正式に名前が
決まっているわけではありませんが、分類の都合上こう呼んでいます。同等結合と
違って、比較演算子で列を結び、各テーブルの行を取り出します。
• 自己結合(self-join)または再帰結合(reflexive join)は、1 つのテーブルの列を使っ
て値を比較します。
• 外部結合(outer join)は、結合の検索条件(ON 句の検索条件)にしたがって各テーブルの
行を比較し、行のうち結合の検索条件に適合するものだけを取り出します。その他に、一
方または両方のテーブルについて、結合の検索条件に適合しない行も取り出せます。
結合には上の 2 種類がありますが、通常は内部結合の方がよく使用されます。これは、デー
タの絞り込みにも優れ、双方のテーブルの関係をはっきりと把握できるためです。ただし、
外部結合も、結合の検索条件に該当しない行を参考にデータを確認できるという点では有
効です。
結合で使用する列の選択
ここでは、結合に使用する列を選択するための基準について説明します。結合に使用する列
は、少なくとも互いのデータ型に互換性があり、互いに内容が似ている必要があります。た
とえば CHAR 型の列を INTERGER 型の列に結合することはできません。一般的で安全な基
準として、あるテーブルの FOREIGN KEY 列を、これが参照する PRIMARY KEY 列に結合
するようにします。2 つのテーブル上の同一の列を結合する場合も多くあります。たとえ
ば、
「業務」テーブルと「従業員」テーブルがそれぞれ持つ job_code という列を結合できます。
INTEGER、DECIMAL、NUMERIC、FLOAT の各データ型の列はいずれも値が数値ですの
で、比較可能です。CHAR と VARCHAR などの文字列型は、文字列としか比較できません。
ただし、相手側の ASCII データが数値だけで構成されている場合、比較は不可能です。デー
タ型が異なり比較できない場合は、CAST() 関数でデータ型を変換します。CAST() の詳細
は、6-17 ページの「CAST() によるデータ型の変換」を参照してください。
重要
結合処理では、いずれかの行の列に NULL 値が含まれている場合、その行は結果テーブル
に格納されません。ただし、外部結合では、NULL が含まれている行も結果テーブルに抽
出されます。
6-46 埋 め 込 み S Q L ガ イ ド
テーブルの結合
内部結合
InterBase では、内部結合を記述する方法が 2 種類あります。1 つは、従来の SQL アプリケー
ションで結合を記述するときの方法で、これは、互換性や移植性を考慮したものです。従来
の SQL アプリケーションでは結合用のキーワードや記述方法が用意されていませんでし
た。このため、内部結合を記述する場合、SELECT 句の中の FROM 句を使用して、結合する
テーブルを個別に指定する必要があります。また、列は WHERE 句で比較していました。
たとえば、次は従来の SQL アプリケーションの結合処理の例です。ここでは、会社の部署
名、マネージャ(部長)番号、および該当する部署の従業員全員に対する給与の三分の一
以上を支給されているマネージャ(部長)の給与額が出力されます。
EXEC SQL
DECLARE BIG_SAL CURSOR FOR
SELECT D.DEPARTMENT, D.MNGR_NO, E.SALARY
FROM DEPARTMENT D, EMPLOYEE E
WHERE D.MNGR_NO = E.EMP_NO
AND E.SALARY*2 >= (SELECT SUM(S.SALARY) FROM EMPLOYEE S
WHERE D.DEPT_NO = S.DEPT_NO)
ORDER BY D.DEPARTMENT;
もう 1 つは、新たに採用されたもので、JOIN 構文を使って結合を明示的に記述する方法で
す。この記述方法は、SQL-92 に準拠しています。構文は次のとおりです。
SELECT col [, col ...] | *
FROM <tablerefleft> [INNER] JOIN <tablerefright>
[ON <searchcondition>]
[WHERE <searchcondition>];
この新しい方法では、FROM 句で JOIN キーワードを使って結合を明示的に宣言します。
JOIN キーワードの左側の <tablerefleft> は比較に使用するテーブルで、このテーブルを左
テーブル(left table)と呼びます。また、<tablerefright> も比較の際に使用するテーブルで、
このテーブルを右テーブル(right table)と呼んでいます。結合の条件(各テーブルの列)は、
ON 句に記述します。WHERE 句には、返される行を限定するための検索条件を記述します。
たとえば、上記の従来の JOIN 処理を新しい記述方法で書き直すと、次のようになります。
EXEC SQL
DECLARE BIG_SAL CURSOR FOR
SELECT D.DEPARTMENT, D.MNGR_NO, E.SALARY
FROM DEPARTMENT D INNER JOIN EMPLOYEE E
ON D.MNGR_NO = E.EMP_NO
WHERE E.SALARY*2 > (SELECT SUM(S.SALARY) FROM EMPLOYEE S
WHERE D.DEPT_NO = S.DEPT_NO)
ORDER BY D.DEPARTMENT;
この新採用の JOIN 構文にはいくつか利点があります。まず、結合を明示的に記述すること
ができるため、ソースコードを読む際にプログラムの内容がはっきりします。
ON 句には結合条件を指定します。WHERE 句には、返される列を制限する条件を指定でき
ます。
第 6 章 データ処理
6-47
テーブルの結合
なお FROM 句では、使用するテーブルの優先順位を定義することもできます。したがって、
結合をネストして 3 つ以上のテーブルを結合することができます。結合のネストの詳細は、
6-51 ページの「ネストされた結合」を参照してください。
同等結合の記述
同等結合とは、2 つのテーブルのある列を使用して、同じ値をもとに行を取り出すような内
部結合を言います。この同等結合は、結合処理の中で最も頻繁に使用されます。同等結合で
は、ON 句は必ず、次のように等号を使って記述します。
ON t1.column = t2.column
たとえば、次の結合では、COUNTRIES テーブルの行のうち、CAPITAL 列の値(首都の名
前)と同じ値が CITIES テーブルの NAME 列にあれば、国名、首都名、首都の人口が出力
されます。
EXEC SQL
DECLARE CAPPOP CURSOR FOR
SELECT COU.NAME, COU.CAPITAL, CIT.POPULATION
FROM COUNTRIES COU JOIN CITIES CIT ON CIT.NAME = COU.CAPITAL
WHERE COU.CAPITAL NOT NULL
ORDER BY COU.NAME;
上 の 例 で は、ON 句 で、CITIES テーブルの NAME 列の値が COUNTRIES テーブルの
CAPITAL 列の値と等しい場合に行が取り出されるように検索条件を記述しています。ま
た、WHERE 句では、NOT NULL を使用して、COUNTRIES テーブルの CAPITAL 列の値が
NULL のときは行を取り出さないように指定しています。
比較結合の記述
比較結合とは、比較演算子を使って 2 つのテーブルの列の値を比較し、行を取り出すよう
な内部結合を言います。また、非同等結合とも呼んでいます。たとえば比較結合では、一方
のテーブルの列の値ともう一方の列の値を比較し、どちらか値が小さい側の行を取り出す
といったことができます。比較結合の場合、ON 句は次のようになります。
ON t1.column <operator> t2.column
上で、<operator> は InterBase で使用可能な比較演算子を表します。有効な比較演算子の詳
細は、6-7 ページの「式での比較演算子の使い方」を参照してください。
たとえば、次の結合では、カナダの州のうち、アメリカのアラスカ州より面積の大きいも
のがあれば、その情報が出力されます。
EXEC SQL
DECLARE BIGPROVINCE CURSOR FOR
SELECT S.STATE_NAME, S.AREA, P.PROVINCE_NAME, P.AREA
FROM STATES S JOIN PROVINCE P ON P.AREA > S.AREA AND
P.COUNTRY = 'Canada'
WHERE S.STATE_NAME = 'Alaska';
この例では、まず、ON 句の比較演算子を使った検索条件によって、カナダの州全部とアメ
リカの州全部とで相互に面積の比較が行われます。この後、WHERE 句により、アメリカの
州がアラスカに限定され、最終的にアラスカよりも面積の大きいカナダの州が出力されま
す。
6-48 埋 め 込 み S Q L ガ イ ド
テーブルの結合
自己結合の記述
自己結合とは、1 つのテーブルの中の列をもとにデータを取り出す内部結合を言います。た
とえば、RIVERS というテーブルに、河川名と、その河川が流れ込む合流河川が記録されて
いたとします。すべての河川が別の河川に合流しているわけではありません。このため、こ
のテーブルを使用して、別の河川に合流する河川を拾い出してみます。この場合は、自己
結合を利用できます。
EXEC SQL
DECLARE RIVERSTORIVERS CURSOR FOR
SELECT R1.RIVER, R2.RIVER
FROM RIVERS R1 JOIN RIVERS R2 ON R2.OUTFLOW = R1.RIVER
ORDER BY R1.RIVER, R2.SOURCE;
上の例のように、自己結合では、JOIN の両側のテーブルは同一のため、それぞれ異なる相
関名を付けなければなりません(上の例では、R1、R2 という相関名を割り当てている)。相
関名の割り当ておよび使い方の詳細は、6-25 ページの「相関名の宣言と使い方」を参照し
てください。
外部結合
外部結合では、一方のテーブルからすべての行が取り出され、もう一方のテーブルからは
検索条件に合致した行だけが取り出されます。このほか、両方のテーブルの行を全部取り出
すこともできますが、この外部結合はあまり利用されません。次の文は外部結合の構文です
が、内部結合の構文とよく似ています。
SELECT col [, col ...] | *
FROM <tablerefleft> {LEFT | RIGHT | FULL} [OUTER] JOIN
<tablerefright> [ON <searchcondition>]
[WHERE <searchcondition>];
外部結合には 3 つの型があり、いずれかを指定しなければなりません。指定できる型は次の
とおりです。
• 左外部結合(left outer join)では、JOIN キーワードの左側のテーブルの行が全部取り出され
ます。右側のテーブルからは、検索条件に合致する行だけが取り出されます。
• 右外部結合(right outer join)では、JOIN キーワードにある右側のテーブルの行が全部取り
出されます。左側のテーブルからは、検索条件に合致する行だけが取り出されます。
• 完全外部結合(full outer join)では、ON 句の検索条件とは無関係に、左側と右側の両方の
テーブルの行が全部取り出されます。
外部結合は、検索条件に該当するデータを取り出すとともに、検索条件には合致しなくて
も関連するデータを同時に確認するときに有効です。たとえば、外部結合を使用して、河川
の源流がある国を取り出すと同時に、源流を持たない国を取り出して比較することができ
ます。
左外部結合の記述
外部結合の中では、左外部結合がよく利用されます。次は、左外部結合の例で、ここでは、
河川の源流を持つ国の他に、源流のない国も併せて取り出されます。なお、COUNTRIES
テーブルの COUNTRY 列の値が NULL のときは、国名は取り出されません。
第 6 章 データ処理
6-49
テーブルの結合
EXEC SQL
DECLARE RIVSOURCE CURSOR FOR
SELECT C.COUNTRY, R.RIVER
FROM COUNTRIES C LEFT JOIN RIVERS R ON R.SOURCE = C.COUNTRY
ORDER BY C.COUNTRY;
ON 句を使用すると、FROM 句で結合の検索条件を指定できます。ON 句では、検索条件を
記述して、右テーブルの列の値をもとに行を限定することができます。一方、上の記述には
ありませんが、WHERE 句で検索条件を記述することによって、左テーブル(外部のテーブ
ル)の列の値に基づいて行をさらに絞り込むことができます。
右外部結合の記述
右外部結合では、JOIN キーワードの右側にあるテーブルの行が全部取り出されます。これ
に対して、左側のテーブルからは、検索条件に合致する行だけが取り出されます。たとえ
ば、次の右外部結合では、河川名と、その源泉がある国名が取り出され、さらに河川の源
泉を持たない国も出力されます。
EXEC SQL
DECLARE RIVSOURCE CURSOR FOR
SELECT R.RIVER, C.COUNTRY
FROM RIVERS.R RIGHT JOIN COUNTRIES C ON C.COUNTRY = R.SOURCE
ORDER BY C.COUNTRY;
ヒント
上記の例でもそうですが、左外部結合の場合、LEFT を RIGHT に書き直して JOIN の両側の
テーブルを相互に入れ替えると、処理内容の同じ右外部結合ができます。逆の場合も同様
です。
完全外部結合の記述
完全外部結合では、ON 句の検索条件とは無関係に、左側と右側の両方のテーブルの行が全
部取り出されます。ただし、列に格納されている値が NULL のときは、データは取り出さ
れません。完全外部結合は、異なるテーブルに同種のデータが格納されている場合に、デー
タが間違っていないかどうかを検証するときなどに便利です。
たとえば、複数のテーブルに同じ都市名が散らばって収められていたとします。また、テー
ブルにトリガーが設定されておらず、このため別のテーブルに対するデータの自動入力は
行われていないものとします。この場合、各テーブルの都市名の照合と検査には、完全外
部結合が必要になります。たとえば、次の例は、COUNTRIES、CITIES、NATIONAL_PARKS
という 3 つのテーブルから都市名を全部取り出す場合の完全外部結合です。
EXEC SQL
DECLARE ALLCITIES CURSOR FOR
SELECT DISTINCT CIT.CITY, COU.CAPITAL, N.PARKCITY
FROM (CITIES CIT FULL JOIN COUNTRIES COU) FULL
JOIN NATIONAL_PARKS N;
上の例では、テーブルが 3 つあるため、最初の完全外部結合をネストにしてあります。この
ため、最初に CITIES と COUNTRIES の 2 つのテーブルの行がすべて取り出され、それをも
とに結果テーブルが作成されます。続いて、この結果テーブルを左テーブルとして、また
NATIONAL_PARKS を右テーブルとして、完全外部結合処理が再度行われます。ネストさ
れた結合の詳細は、6-51 ページの「ネストされた結合」を参照してください。
6-50 埋 め 込 み S Q L ガ イ ド
サブクエリー
メモ
複数のテーブルに同じデータまたは関連するデータを入力するときは、通常、トリガーを
作成すると便利です。このトリガーを使用して、異なるテーブルのデータを同時に更新す
ることができます。トリガーの詳細は、『データ定義ガイド』を参照してください。
外部結合のソート / マージの最適化
外部結合アルゴリズムのソート / マージ オプションは、外部結合の外部ストリームと内部
ストリームを認識するようになりました。また、一致する行が内部ストリームにない場合、
外部行を NULL 値を持つ内部行と一致させるようになりました。
完全外部結合(両側外部結合)の場合は、第 1 ストリームについて一致する行と NULL に
一致する行が生成された後、外部ストリームと内部ストリームが交換されます。第 1 スト
リームが内部ストリームになり、第 2 ストリームであったものが外部ストリームになりま
す。その次に、これらの行が左外部結合され、外部ストリームが NULL に一致する行のみ
が生成されます。結合条件に一致する行は除外されます。それらの行は、第 1 段階で 2 つ
のストリームが交換される前に生成されたからです。
ネストされた結合
SELECT 文の FROM 句では、かっこの中にテーブル(またはテーブルリファレンス)の名
前、JOIN キーワード、ON 句を記述し、ネストされた結合を作成することができます。結
合の実行時には、このネストされた結合の結果テーブルが作成されます。この結果テーブ
ルは、データベースに格納されている実際のテーブルと同じように扱われます。このテーブ
ルリファレンスは柔軟かつ強力で、これを活用することで 1 つの SELECT 文で複雑な結合
を要領よく記述することができます。
たとえば、次の文は、ネストされた左外部結合の例です。ここでは、まず、COUNTRIES
テーブルの COUNTRY 列の国名と同じ国名がない行も含め、CITIES テーブルに記録されて
いる都市名が全部取り出され、結果テーブルが作成されます。次に、この結果テーブルを左
テーブルとして、内部結合が実行されます。この結果、プロのスポーツチームのある都市
だけが取り出され出力されます。また、そのチーム名とスポーツの種類も出力されます。
DECLARE SPORTSCITIES CURSOR FOR
SELECT COU.COUNTRY, C.CITY, T.TEAM, T.SPORT
FROM (CITIES CIT LEFT JOIN COUNTRIES COU ON COU.COUNTRY =
CIT.COUNTRY) INNER JOIN TEAMS T ON T.CITY = C.CITY
ORDER BY COU.COUNTRY;
左外部結合の詳細は、6-49 ページの「外部結合」を参照してください。
サブクエリー
サブクエリーとは、WHERE 句でかっこを使ってネストされた SELECT 文を言います。この
サブクエリーは、それ自体が検索条件として機能します。このため、サブクエリーを使用
して、外部クエリー(親クエリー)よりも下のレベルで行を限定することができます。サブ
クエリーでは、親クエリーと同じテーブルを指定することもでき、別のテーブルを指定す
ることもできます。
サブクエリーの基本構文は次のようになります。
第 6 章 データ処理
6-51
サブクエリー
SELECT [DISTINCT] col [, col ...]
FROM <tableref> [, <tableref> ...]
WHERE {expression {[NOT] IN | comparison_operator}
| [NOT] EXISTS} (SELECT [DISTINCT] col [, col ...]
FROM <tableref> [, <tableref> ...]
WHERE <search_condition>);
サブクエリーは検索条件のため、通常、親クエリーより先に評価されます。この後、サブ
クエリーの結果をもとに、親クエリーによって取り出す行が決定されます。ただし、サブク
エリーが相関的なサブクエリーの場合は例外です。相関的なサブクエリーでは、親クエリー
から情報を得て、その後で処理が行われます。相関的なサブクエリーの詳細は、6-53 ペー
ジの「相関的なサブクエリー」を参照してください。
サブクエリーは、親クエリーの WHERE 句にどういった演算子が指定されているかによっ
て、記述の方法が異なります。記述の方法には、次の 3 とおりあります。
• 親クエリーの WHERE 句に IN 演算子が使用されている場合は、複数の値が返されるように
サブクエリーを記述します。また、比較演算子とともに ALL、ANY、SOME のいずれかの
演算子が使用されているときも同様です。
• 親クエリーの WHERE 句に比較演算子が使用されているときは、サブクエリーは 1 つの値
が返されるように記述しなければなりません。
• 親クエリーの WHERE 句に EXISTS 演算子が使用されているときは、EXISTS が必要とする
構文を使って記述しなければなりません。
サブクエリーの中には、かっこを使ってさらにサブクエリーをネストすることができます。
このサブクエリーも検索条件となり、このようにして、何層にもわたってサブクエリーを
作成することができます。
基本的なサブクエリー
あるテーブルの中の列をもとにデータを取り出す場合、自己結合を使用できます。ただし、
自己結合ではデータの取り出しが難しいこともあり、サブクエリーは、このような場合に
利用価値があります。たとえば、COUNTRIES テーブルに国名と面積が記録されており、こ
のテーブルを使って面積が平均より大きい国を検索する場合、この処理は自己結合ではで
きません。一方、サブクエリーを使用すると検索が容易です。
EXEC SQL
DECLARE LARGECOUNTRIES CURSOR FOR
SELECT COUNTRY, AREA
FROM COUNTRIES
WHERE AREA > (SELECT AVG(AREA) FROM COUNTRIES);
ORDER BY AREA;
上の例では、親クエリーでもサブクエリーでも同じテーブルを指定しています。これに対し
て、指定先のテーブルは親クエリーとサブクエリーで異なっていてもかまいません。たとえ
ば、次は、親クエリーで CITIES テーブルを、サブクエリーで COUNTRIES テーブルを指定
している例です。
EXEC SQL
DECLARE EUROCAPPOP CURSOR FOR
6-52 埋 め 込 み S Q L ガ イ ド
サブクエリー
SELECT CIT.CITY, CIT.POPULATION
FROM CITIES CIT
WHERE CIT.CITY IN (SELECT COU.CAPITAL FROM COUNTRIES COU
WHERE COU.CONTINENT = 'Europe')
ORDER BY CIT.CITY;
また、上の例では、相関名を使ってテーブルを区別していますが、親クエリーとサブクエ
リーで指定するテーブルが異なる場合は、相関名は必要ありません。一方、親クエリーとサ
ブクエリーで指定するテーブルが同じで、また同じ列名を使って処理を行う場合には相関
名が必要です。ただし、どのような場合でも相関名を使用することが優れたプログラミン
グ技法と言えます。相関名の使い方の詳細は、6-25 ページの「相関名の宣言と使い方」を
参照してください。
相関的なサブクエリー
サブクエリーのうち、親クエリーによって与えられる値をもとに処理を行うサブクエリー
を相関的なサブクエリーと呼んでいます。また、親クエリーによって評価される行はそれぞ
れ値が異なるため、相関的なサブクエリーでは、その各行について一度ずつ処理が行われ
るのが一般的です。
たとえば、次は、CITIES テーブルの中に同じ国の都市名が 3 つ以上あったときに、その国
名が出力されるクエリーの例です。ここでは、親クエリーによって、COUNTRIES テーブル
に格納されている国名が行ごとに 1 つずつ取り出されます。取り出された国名は、次に、サ
ブクエリーの WHERE 句に渡され、その国に属する都市が CITIES テーブルの CITY 列にあ
るかどうかが検査されます。その国に属する都市が見つかったときは、COUNT() 関数に
よってカウントされます。このようにして、COUNT() 関数の値が 3 になったとき、親クエ
リーによって渡された行が最終的に取り出されます。
EXEC SQL
DECLARE TRICITIES CURSOR FOR
SELECT COUNTRY
FROM COUNTRIES COU
WHERE 3 <= (SELECT COUNT (*)
FROM CITIES CIT
WHERE CIT.CITY = COU.CAPITAL);
上の例は簡単な相関的なサブクエリーですが、このようなサブクエリーをいくつかネスト
して組み合わせることで、複雑なクエリーを作成できます。たとえば、次は、その国の面積
がすべての国の平均面積より大きく、かつ海抜 30 メートル以下に少なくとも 1 つは都市の
ある国が見つかった場合、その国名、首都、最大都市が出力されるクエリーの例です。
EXEC SQL
DECLARE SEACOUNTRIES CURSOR FOR
SELECT CO1.COUNTRY, C01.CAPITAL, CI1.CITY
FROM COUNTRIES C01, CITIES CI1
WHERE CO1.COUNTRY = CI1.COUNTRY AND CI1.POPULATION =
(SELECT MAX(CI2.POPULATION)
FROM CITIES CI2 WHERE CI2.COUNTRY = CI1.COUNTRY)
AND CO1.AREA >
第 6 章 データ処理
6-53
データの挿入
(SELECT AVG (CO2.AREA)
FROM COUNTRIES C02 WHERE EXISTS
(SELECT *
FROM CITIES CI3 WHERE CI3.COUNTRY = CO2.COUNTRY
AND CI3.ALTITUDE <= 30));
上の例のように、サブクエリーを使って複数のクエリーを組み合わせる場合、クエリーで
使用するテーブル(FROM 句で指定するテーブル)に対して、そのクエリー専用の相関名
を宣言しなければなりません。また、クエリーの WHERE 句では、この専用の相関名を使っ
て列を指定し、検索条件を記述する必要があります。この方法で、所定の内容のテーブル
(WHERE 句で行が限定されたテーブル)を使って SELECT 句の処理が行われるようになり
ます。相関名の詳細は、6-25 ページの「相関名の宣言と使い方」を参照してください。
UPDATE 文における相関サブクエリーのインデックス最適化
適切なインデックスが定義されている場合、UPDATE 文内の相関サブクエリーでは、インデッ
クスによる検索を用いて行が取り出されるようになりました。UPDATE 文内の相関サブクエ
リーでインデックスによるアクセスを行うには、以下のサンプル コードのように記述しま
す。
UPDATE A SET A.C1 = (SELECT B.C1 FROM B WHERE B.C2 = A.C2)
B.C2 にインデックスが設定されている場合、外部テーブル A の行は既に取得されているの
で、InterBase はインデックスを用いて、B.C2 = A.C2 の条件に一致する行をテーブル B か
ら取り出します。
データの挿入
テーブルに新規の行を挿入(追加)する場合、INSERT 文を使用します。なお、新規の行の
追加が可能なのは、そのテーブルについて INSERT 特権が与えられているユーザーに限ら
れます。また、ストアドプロシージャによる追加の場合も、そのストアドプロシージャに
テーブルの INSERT 特権が与えられていることが必要です。
INSERT 文では、データの挿入方法に次の 2 種類があります。
• VALUES 句による挿入:複数の値を指定して追加するときに使用します。指定する値とし
ては、ハードコードされた値のほか、変数も記述できます。
• SELECT 文による挿入:既存のテーブルの値を取り出し、その値を別のテーブルに追加す
る場合に使用します。
INSERT の構文は次のとおりです。
INSERT [TRANSACTION name] INTO table [(col [, col ...])]
{VALUES (<val>[:ind] [, <val>[:ind] ...])
| SELECT <clause>};
上の構文で、INTO の右にはテーブル名を、その右にはテーブルの列名を指定します。ここ
で指定した列にデータが格納されます。この列名は DSQL アプリケーションでは記述しな
くてもかまいません。DSQL アプリケーションで列名を記述しなかった場合、各データが、
そのテーブルに設定されている列の順番で挿入されます。また、挿入するデータの数が列の
数より少なかったときは、余った列には 0 が格納されます。
6-54 埋 め 込 み S Q L ガ イ ド
データの挿入
VALUES によるデータの挿入
VALUES 句では複数の値を指定することができ、ここで指定した値を持つ行がテーブルに
挿入されます。また、実行時にユーザーが値を追加する場合も、この VALUES 句を使用し
ます。VALUES 句では、ハードコードされた値の他に変数を指定することもできます。
たとえば、次の文では、DEPARTMENT テーブルに新規の行が追加されると、数値と文字
列の 2 つのハードコードされた値がそれぞれ DEPT_NO と DEPARTMENT という 2 つの列
に挿入されます。
EXEC SQL
INSERT INTO DEPARTMENT (DEPT_NO, DEPARTMENT)
VALUES (7734, 'Marketing');
上の例で、VALUES 句で指定している列の数は 2 つですが、DEPARTMENT テーブルの列
は他にもあります。この場合、値が挿入されなかった列には NULL が格納されます。
次の C のコードは、ユーザーにデータの入力を求め、そのデータを VALUES 句を使って
DEPARTMENT テーブルに追加する例です。ここでは、VALUES 句で変数を指定し、この
変数を介して値を挿入しています。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char department[26], dept_no[16];
int dept_num;
EXEC SQL
END DECLARE SECTION;
. . .
printf("Enter name of department: ");
gets(department);
printf("¥nEnter department number: ");
dept_num = atoi(gets(dept_no));
EXEC SQL
INSERT INTO COUNTRIES (DEPT_NO, DEPARTMENT)
VALUES (:dept_num, :department);
VALUES 句で変数を指定する場合、各変数の先頭には必ずコロン(:)を付けます。このコ
ロンがないと、変数がテーブルの列名として解釈されてしまいます。
SELECT によるデータの挿入
SELECT 文を使用して、テーブルにすでに格納されている行を取り出し、同じテーブルまた
は別のテーブルに追加することができます。SELECT 文では、VALUES 句と同じく挿入する
値を直接指定できるほか、列名を使って挿入する値を指定することもできます。たとえば、次
の INSERT 文は、OLDDEPT テーブルの行のうち、DEPARTMENT 列の値が "Documentation"
である行を取り出し、その行を DEPARTMENT テーブルに追加(コピー)する例です。デー
第 6 章 データ処理
6-55
データの挿入
タとしては、部署番号、部署名、
予算が挿入されます。また、SELECT 文で直接 "Publications"
を指定しているため、この値が DEPARTMENT テーブルの DEPARTMENT 列に挿入されるこ
とになります。
EXEC SQL
INSERT INTO DEPARTMENTS (DEPT_NO, DEPARTMENT, BUDGET)
SELECT DEPT_NO, 'Publications', BUDGET
FROM OLDDEPT
WHERE DEPARTMENT = 'Documentation';
SELECT では、算術演算子を記述することもできます。たとえば、社員管理のアプリケー
ションで、名前の他に社員番号を連番で割り当てているとします。したがって、新しく社員
が入社したときは、EMPLOYEE テーブルに新しい行を追加するとともに、番号を重複しな
いように割り当てる必要があります。このような場合、SELECT 文を使用して、それまでの
番号のうち最大のものを探し、それに 1 を加えるのが便利です。次の文は、その処理例で
す。例では、SELECT で lastname と firstname という 2 つの変数を指定し、この変数を介して
データをそれぞれ LAST_NAME と FIRST_NAME の 2 つの列に挿入しています。
EXEC SQL
INSERT INTO EMPLOYEE (EMP_NO, LAST_NAME, FIRST_NAME)
SELECT (MAX(EMP_NO) + 1, :lastname, :firstname)
FROM EMPLOYEE;
NULL を含んだ新規行の追加
テーブルに新規の行を追加する場合、列によっては値が必要ないか、その時点で挿入する
値が未定なこともあります。このような場合は、行の挿入時に、その列に NULL を割り当
てておくようにします。列に NULL を挿入する方法には、次の 3 種類があります。
• 列を無視します(故意に列を指定しない)
。
• NULL 値を指定して挿入します。SQL では、これが一般的な方法です。
• インジケータ変数を使用します。
(ユーザーが値を入力しなかったときには NULL が格納さ
れますが、インジケータ変数を使用することで、この NULL をトラップできます。
列の無視による NULL の挿入
INTO 句で列を指定しない場合、その列には自動的に NULL が割り当てられます。これは、
挿入時、参照元の値が見つからない列に対して、フラグとして NULL が自動的に格納され
るためです(列の属性が NULL に設定されている場合)。たとえば、DEPARTMENT テーブ
ルに HEAD_DEPT、MNGR_NO、BUDGET という列があったとします。この場合、この 3 つ
の列を指定から除外して、次のような INSERT 文を記述したとします。
EXEC SQL
INSERT INTO DEPARTMENT (DEPT_NO, DEPARTMENT)
VALUES (:newdept_no, :newdept_name);
上の例では、HEAD_DEPT、MNGR_NO、BUDGET という列を指定していないため、追加
された行では、この 3 つの列には NULL 値が格納されます。
メモ
既存のテーブルに列を追加した場合、すべての行のその列に NULL が格納されます。
6-56 埋 め 込 み S Q L ガ イ ド
データの挿入
指定による NULL の挿入
行の挿入時、列の値を特に指定しない場合、その列には NULL が挿入されます。SQL では、
列に NULL を挿入する際、この方法がよく使用されます。このほか、InterBase では、INSERT
文で NULL を指定して、列に NULL を格納することもできます。
たとえば、次の INSERT 文では、DEPARTMENT テーブルに新規の行が追加されると同時
に、7 つの列に値が格納されます。このうち、4 つの列には NULL が挿入されます。
EXEC SQL
INSERT INTO DEPARTMENT
(DEPT_NO, DEPARTMENT, HEAD_DEPT, MNGR_NO, BUDGET,
LOCATION, PHONE_NO)
VALUES (:dept_no, :dept_name, NULL, NULL, 1500000, NULL, NULL);
インジケータ変数による NULL の挿入
NULL をトラップし、割り当てる方法として、インジケータ変数を使用する方法がありま
す。この方法は、ユーザーによるデータの入力があり、また値の未入力も受け付ける(ユー
ザーがデータを入力しない場合も対応できる)アプリケーションでは、必ず使用しなけれ
ばなりません。また、インジケータ変数を使用することで、NULL の検索が可能になりま
す。つまり、InterBase ではユーザーからの値の入力がなかった場合、列には自動的に NULL
が格納されます。このとき、列のデータ型が数値だった場合、NULL は複数の 0 として格
納されます。また、列のデータ型が文字だったときは、NULL は複数のスペースとして格
納されます。ただし、この 0 とスペースはいずれも有効なデータとして認識されるため、
ユーザーが入力したデータが NULL であるか、または実際の 0 またはスペースなのか区別
がつかなくなることもあります。
このような場合、インジケータ変数を使用することにより、ユーザーの入力が NULL であっ
たかどうかを識別することができます。このインジケータ変数には、データが NULL であ
るかどうかのフラグを格納します。インジケータ変数の記述は、次の手順で行います。
1
2
インジケータ変数として使用する変数を宣言します。
ユーザーが入力した値をチェックし、インジケータ変数を次のいずれかの値に設定します。
0
–1
3
ユーザーの入力を受ける変数にデータがあった場合
ユーザーの入力を受ける変数にデータがなかった場合
INSERT 文で、変数とインジケータ変数を関連付けます。この場合の構文は次のとおりで
す。
INSERT INTO table (<col> [, <col> ...])
VALUES (:variable [INDICATOR] :indicator
[, :variable [INDICATOR] :indicator ...]);
メモ
INDICATOR キーワードはオプションです。
たとえば、次は、ユーザーに部署名、部署番号、部署の予算の入力を求める C のコード例
です。このうち予算の入力に対して検査を行います。値の入力がなかった場合、インジケー
タ変数である bi を –1 に設定しています。一方、入力があったときには bi を 0 に設定してい
ます。プログラムの最後では、INSERT を使って DEPARTMENT テーブルにデータを格納し
第 6 章 データ処理
6-57
データの挿入
ています。したがって、ユーザーの入力がないため BUDGET 列に NULL が格納されたとき
でも、それが NULL なのか、実際の 0 またはスペースなのかをこのインジケータ変数で確
認することができます。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
short bi; /* インジケータ変数の宣言 */
char department[26], dept_no_ascii[26], budget_ascii[26];
long num_val; /* 予算を挿入するためのホスト変数 */
short dept_no;
EXEC SQL
END DECLARE SECTION;
. . .
printf("Enter new department name: ");
gets(cidepartment);
printf("¥nEnter department number: ");
gets(dept_no_ascii);
printf("¥nEnter department’s budget: ");
gets(budget_ascii);
if (budget_ascii = "")
{
bi = -1; num_val = 0;
}
else
{
bi = 0;
num_val = atoi(budget_ascii);
}
dept_no = atoi(dept_no_ascii);
EXEC SQL
INSERT INTO DEPARTMENT (DEPARTMENT, DEPT_NO, BUDGET)
VALUES (:department, :dept_no, :num_val INDICATOR :bi);
. . .
上の例は、NULL を格納する際のインジケータ変数の使い方ですが、テーブルからデータ
を取り出す場合もインジケータ変数を使って NULL を検査することができます。テーブル
から取り出した NULL のトラップの詳細は、6-39 ページの「INDICATOR によるインジ
ケータ変数の設定」を参照してください。
ビューを使ったデータの挿入
新規の行はビューを介してテーブルに挿入することもできます。ただし、この場合、次の
ような条件が必要になります。
• ビューが更新可能であること。更新可能なビューの詳細は、
『データ定義ガイド』を参照
してください。
6-58 埋 め 込 み S Q L ガ イ ド
データの挿入
• 使用するビューに WITH CHECK OPTION が設定されていること
• 使用するビューの INSERT 特権がユーザーに与えられていること。ストアドプロシージャ
の場合は、そのストアドプロシージャに対して、使用するビューの INSERT 特権が与えら
れていること
ビューを使って行を追加する場合、データの挿入が可能なのは、そのビューに用意されて
いる列に限られます。したがって、行の追加先となるテーブルの列のうち、ビューに用意さ
れていない列に対しては、自動的に NULL が格納されます。たとえば、PART_DEPT という
ビューがあり、このビューは次のようにして作成されていたとします。
EXEC SQL
CREATE VIEW PART_DEPT
(DEPARTMENT, DEPT_NO, BUDGET)
AS SELECT DEPARTMENT, DEPT_NO, BUDGET
FROM DEPARTMENT
WHERE DEPT_NO NOT NULL AND BUDGET > 50000
WITH CHECK OPTION;
上の例では、PART_DEPT ビューの作成元となっているテーブルは DEPARTMENT だけで
す。また、列としては DEPARTMENT、DEPT_NO、BUDGET の 3 つが指定されており、こ
の 3 つの列に対してデータの挿入が可能です。さらに、WITH CHECK OPTION が設定され
ているので、挿入できるのは、ビューで指定されている範囲の値(この例では、BUDGET
が 50000 を 超 え る)だ けです。 この PART_DEPT ビューを使用して、新規の行を
DEPARTMENT テ ー ブ ル に追加する場合は、次のようになります。ここでは、部署が
Publications のデータを 1 行追加します。
EXEC SQL
INSERT INTO PART_DEPT (DEPARTMENT, DEPT_NO, BUDGET)
VALUES ('Publications', '7735', 1500000);
上でも説明したように、テーブルにあってビューにない列に対しては NULL が格納されま
す。したがって、ビューに用意されていない列が DEPARTMENT テーブルにあったときは、
その列にすべて NULL が入力されます。
ビューの作成の詳細は、第 5 章「データ定義文」を参照してください。CREATE VIEW 構
文の詳細は、『言語リファレンス』を参照してください。
メモ
トリガーを使用して、更新不可のビューを更新する方法のヒントについては、
『データ定義
ガイド』を参照してください。
INSERT でのトランザクション名の指定
InterBase では、SQL アプリケーションが複数のトランザクションを同時に実行できます。
ただし、次の条件が必要です。
• トランザクションがそれぞれ SET TRANSACTION 文で事前に宣言されていること。
トラン
ザクション処理と命名の詳細は、第 4 章「トランザクションの操作」を参照してください。
• データ操作文(SELECT、INSERT、UPDATE、DELETE、DECLARE、OPEN、FETCH、CLOSE)
で TRANSACTION 句が使用されており、関連するトランザクションが指定されているこ
と。
第 6 章 データ処理
6-59
データの更新
• SQL 文が DSQL ではないこと。DSQL では、ユーザーがトランザクション名を定義すること
はできません。
上記のように、TRANSACTION 句でトランザクション名を指定することによって、INSERT
文でも任意のトランザクションを使ってテーブルに対する行の挿入が可能になります。こ
の場合、構文は次のようになります。
INSERT TRANSACTION name INTO table (col [, col ...])
なお、トランザクションを 1 つしか使用しないプログラムでは、TRANSACTION 句は記述
しなくてもかまいません。TRANSACTION 句の記述は、複数のトランザクションを使用す
るプログラムだけで必要です。ただし、複数のトランザクションを使用するプログラムで
も、デフォルトトランザクション(GDS__TRANS)を使用しない場合は記述しなければな
りません。たとえば、次のように記述した場合、INSERT は T1 というトランザクションと
ともに機能し、T1 のもとで挿入が行われるようになります。
EXEC SQL
INSERT TRANSACTION T1 INTO DEPARTMENT (DEPARTMENT, DEPT_NO, BUDGET)
VALUES (:deptname, :deptno, :budget INDICATOR :bi);
データの更新
既存の行のデータを更新(変更)するときは、UPDATE 文を使用します。ただし、行の更
新が可能なのは、そのテーブルについて UPDATE 特権が与えられているユーザーに限られ
ます。また、ストアドプロシージャによる更新の場合も、そのストアドプロシージャにテー
ブルの UPDATE 特権が与えられていなければなりません。UPDATE の構文は次のとおりで
す。
UPDATE [TRANSACTION name] table
SET col = <assignment> [, col = <assignment> ...]
WHERE <search_condition> | WHERE CURRENT OF cursorname
[ORDER BY <order_list>]
[ROWS <value> [TO <upper_value>] [BY <step_value>][PERCENT][WITH TIES]];
UPDATE では、SET 句を使って指定した列が更新の対象となります。言い換えれば、SET 句
で指定しなかった列は更新されません。<assignment> には値を指定します。既存の値は、
この値に置き換えられます。また、1 つの UPDATE 文で、テーブルの複数行に対して一度
に変更を行うこともできます。次の例は、1 行のデータを変更する場合の記述です。
EXEC SQL
UPDATE DEPARTMENT
SET DEPARTMENT = 'Publications'
WHERE DEPARTMENT = 'Documentation';
上の例では、WHERE 句の検索条件により、変更対象の行が 1 行に限定されています。同じ
変更をテーブルの複数の行に反映する場合が、WHERE 句としては一般的です。たとえば、
次 の 例 で は、EMPLOYEE テーブル(社員名簿)の DEPARTMENT 列(所属部署)に
“Documentation” という値が入っている場合、その値がすべて “Publications” に変更されま
す。UPDATE 文は、次のようになります。
EXEC SQL
UPDATE DEPARTMENT
6-60 埋 め 込 み S Q L ガ イ ド
データの更新
SET DEPARTMENT = 'Publications'
WHERE DEPARTMENT = 'Documentation';
上記のように、複数行にわたって同じ変更を行う処理を大量更新または検索更新と呼んで
います。
なお、UPDATE 文の WHERE 句では、サブクエリーを記述することもできます。このサブ
クエリーでは、複数のテーブルを指定することもできます。サブクエリーの詳細は、6-51
ページの「サブクエリー」を参照してください。
複数行の更新
複数行を更新する方法には、基本的に次の 2 種類があります。
• 検索更新:この方法では、複数行のデータに対して同一の変更が一度に実行されます。カー
ソルを使用せずに複数行のデータを自動更新するときに有効です。
• 位置指定更新:カーソルを使って行を取り出し、1 行ごとに更新を行う方法です。ユーザー
による更新を扱う場合に有効な方法で、ユーザーの指示にしたがって行を取り出し、その
つど更新されるように記述します。
位置指定更新よりも検索更新の方がプログラミングは簡単ですが、位置指定更新の方が処
理の点で柔軟です。
検索更新の記述
検索更新は、複数行に対して同じ変更を行う場合に使用します。この更新では、UPDATE の
SET 句に列と値を指定しておいた場合、WHERE 句の検索条件で取り出された行すべての該
当列(SET 句で指定した列)に対して、変更が実行されます。SET 句で指定する値は、定数
または変数のどちらでもかまいません。
たとえば、次に挙げる検索更新の C のコード例では、ユーザーに国名と人口の変動率(パー
セント)の入力を求め、入力された値にしたがって検索更新を行っています。ここでは、変
動率が入力されると、その率にしたがって、ユーザーが指定した国に属する全都市の人口
(POPULATION 列のデータ)が一括して増減されます。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char country[26], asciimult[10];
int multiplier;
EXEC SQL
END DECLARE SECTION;
. . .
main ()
{
printf("Enter country with city populations needing adjustment: ");
gets(country);
printf("¥nPercent change (100%% to -100%%:");
gets(asciimult);
multiplier = atoi(asciimult);
第 6 章 データ処理
6-61
データの更新
EXEC SQL
UPDATE CITIES
SET POPULATION = POPULATION * (1 + :multiplier / 100)
WHERE COUNTRY = :country;
if (SQLCODE && (SQLCODE != 100))
{
isc_print_sqlerr(SQLCODE, isc_status);
EXEC SQL
ROLLBACK RELEASE;
}
else
{
EXEC SQL
COMMIT RELEASE;
}
}
重要
データが配列の場合は、データ型にかかわらず検索更新は実行できません。
位置指定更新の記述
カーソルを使って行を選択して更新を行う方法を位置指定更新と言います。ユーザーに入
力を求め、その入力にしたがって行を 1 行ずつ取り出して更新を行う場合に使用します。こ
の更新では、ユーザーは変更前の値と変更後の値を確認できます。位置指定更新は、次の 7
つの手順で行われます。
1
2
更新処理で必要になる変数を宣言します。
3
4
5
6
7
カーソルを開きます。
カーソルを宣言します。このカーソルは、更新の対象となる行の取り出しに使用しま
す。また、DSQL の場合は、FOR UPDATE 句を記述します。カーソルの宣言と使い方の
詳細は、6-35 ページの「複数行の取り出し」を参照してください。
行を取り出します。
現在値が表示され、新しい値の入力を求められます。
WHERE CURRENT OF 句を使用して、現在取り出されている行を更新します。
上のステップ 3 ~ 6 の処理を繰り返し、取り出し対象となっている行をすべて更新しま
す。
次の文は、位置指定更新の C のコード例です。ここでは、CITIES テーブルに格納されてい
る都市のうち、ユーザーが入力した国に属する都市が順次取り出され、さらにユーザーが
入力した率(パーセント)にしたがって、その都市の人口(POPULATION 列のデータ)が
増減されます。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char country[26], asciimult[10];
6-62 埋 め 込 み S Q L ガ イ ド
データの更新
int multiplier;
EXEC SQL
END DECLARE SECTION;
. . .
main ()
{
EXEC SQL
DECLARE CHANGEPOP CURSOR FOR
SELECT CITY, POPULATION
FROM CITIES
WHERE COUNTRY = :country;
printf("Enter country with city populations needing adjustment: ");
gets(country);
EXEC SQL
OPEN CHANGEPOP;
EXEC SQL
FETCH CHANGEPOP INTO :country;
while(!SQLCODE)
{
printf("¥nPercent change (100%% to -100%%:");
gets(asciimult);
multiplier = atoi(asciimult);
EXEC SQL
UPDATE CITIES
SET POPULATION = POPULATION * (1 + :multiplier / 100)
WHERE CURRENT OF CHANGEPOP;
EXEC SQL
FETCH CHANGEPOP INTO :country;
if (SQLCODE && (SQLCODE != 100))
{
isc_print_sqlerr(SQLCODE, isc_status);
EXEC SQL
ROLLBACK RELEASE;
exit(1);
}
}
EXEC SQL
COMMIT RELEASE;
}
重要
上の例では FOR UPDATE を記述していませんが、記述した場合、カーソルによって一度に
1 行ずつ取り出されます。FOR UPDATE を省略した場合、行は一括して取り出されます。
第 6 章 データ処理
6-63
データの更新
UPDATE による列への NULL の設定
UPDATE では、列の値を NULL に設定することもできます。方法は、UPDATE の SET 句を
使用し、NULL を格納する列を指定します。たとえば、マネージャのいない部署の予算の値
を NULL に設定する場合、記述は次のようになります。
EXEC SQL
UPDATE DEPARTMENT
SET BUDGET = NULL
WHERE MNGR_NO = NULL;
ビューを使った更新
既存の行はビューを介して更新することもできます。ただし、次のような条件が必要にな
ります。
• ビューが更新可能であること。更新可能なビューの詳細は、
『データ定義ガイド』を参照
してください。
• 使用するビューに WITH CHECK OPTION が設定されていること
• 使用するビューの UPDATE 特権がユーザーに与えられていること。ストアドプロシージャ
の場合は、そのストアドプロシージャに対して、使用するビューの UPDATE 特権が与えら
れていること
ビューを使って更新を行う場合、更新が可能なのは、そのビューに用意されている列に限
られます。たとえば、PART_DEPT というビューがあり、このビューは次のようにして作成
されていたとします。
EXEC SQL
CREATE VIEW PART_DEPT
(DEPARTMENT, NUMBER, BUDGET)
AS SELECT DEPARTMENT, DEPT_NO, BUDGET
FROM DEPARTMENT
WITH CHECK OPTION;
上の例では、PART_DEPT ビューの作成元となっているテーブルは DEPARTMENT だけで、
列としては DEPARTMENT、DEPT_NO、BUDGET の 3 つが指定されています。したがって、
ビューを介して更新を行う場合、この 3 つの列に限って処理が可能です。さらに、WITH
CHECK OPTION が設定されているので、ビューで指定されている範囲の値だけが挿入可能
です(上の例では、具体的な範囲の記述は省略)。たとえば、PART_DEPT ビューを使用し
て、DEPARTMENT テーブルの "Publications" 部の予算を更新する場合、記述は次のように
なります。
EXEC SQL
UPDATE PART_DEPT
SET BUDGET = 2505700
WHERE DEPARTMENT = 'Publications';
ビューの作成の詳細は、第 5 章「データ定義文」を参照してください。CREATE VIEW 構
文の詳細は、『言語リファレンス』を参照してください。
6-64 埋 め 込 み S Q L ガ イ ド
データの削除
メモ
トリガーを使用して、更新不可のビューを更新する方法のヒントについては、
『データ定義
ガイド』を参照してください。
UPDATE でのトランザクション名の指定
InterBase では、SQL アプリケーションが複数のトランザクションを同時に実行できます。
ただし、次の条件が必要です。
• トランザクションがそれぞれ SET TRANSACTION 文で事前に宣言されていること。
トラン
ザクション処理と命名の詳細は、第 4 章「トランザクションの操作」を参照してください。
• データ操作文(SELECT、INSERT、UPDATE、DELETE、DECLARE、OPEN、FETCH、CLOSE)
で TRANSACTION 句が使用されており、関連するトランザクションが指定されているこ
と。
• SQL 文が DSQL ではないこと。DSQL では、ユーザーがトランザクション名を定義すること
はできません。
上 記 の よ う に、TRANSACTION 句でトランザクション名を指定することによって、
UPDATE 文で任意のトランザクションを使った更新が可能になります。この場合、構文は
次のようになります。
UPDATE [TRANSACTION name] table
SET col = <assignment> [, col = <assignment> ...]
WHERE <search_condition> | WHERE CURRENT OF cursorname;
複数のトランザクションを使用するプログラムでは、必ず TRANSACTION 句を記述しなけ
れ ば な り ま せ ん。一 方、ト ランザクションを 1 つしか使用しないプログラムでは、
TRANSACTION 句は記述しなくてもかまいません。また、複数のトランザクションを使用
するプログラムでも、同時に複数のトランザクションを使用することがない場合は、記述
の必要はありません。たとえば、次のように記述した場合、UPDATE は T1 というトランザ
クションとともに機能し、T1 のもとで更新が行われるようになります。
EXEC SQL
UPDATE TRANSACTION T1 DEPARTMENT
SET BUDGET = 2505700
WHERE DEPARTMENT = 'Publications';
データの削除
既存の行を削除するときには DELETE 文を使用します。行の削除が可能なのは、そのテー
ブルについて DELETE 特権が与えられているユーザーに限られます。また、ストアドプロ
シージャによる削除の場合も、そのストアドプロシージャにテーブルの DELETE 特権が付
与されていることが必要です。
DELETE の構文は次のとおりです。
DELETE [TRANSACTION name] FROM table
WHERE <search_condition> | WHERE CURRENT OF cursorname
[ORDER BY <order_list>]
[ROWS <value> [TO <upper_value>] [BY <step_value>][PERCENT][WITH TIES]];
第 6 章 データ処理
6-65
データの削除
DELETE で削除を行った場合、FROM 句で指定した行は、列のデータ型にかかわらずテー
ブルから完全に削除されます。
DELETE では、テーブル中の 1 行のほか、複数行を一度に削除することもできます。次の文
は、
DEPARTMENT テーブルから “Channel Marketing” を含んでいる 1 行を削除する例です。
EXEC SQL
DELETE FROM DEPARTMENT
WHERE DEPARTMENT = 'Channel Marketing';
上の例では、WHERE 句の検索条件により、削除対象の行が 1 行に限定されています。同じ
削除条件をテーブルの複数の行に適用する場合が、WHERE 句としては一般的です。たとえ
ば、DEPARTMENT テーブルの行のうち、BUDGET 列の値(予算)が 1000000 ドル未満の
行をすべて削除する場合は、DELETE 文は次のようになります。
EXEC SQL
DELETE FROM DEPARTMENT
WHERE BUDGET < 1000000;
上の文のように、複数行を一度に削除する処理を大量削除または検索削除と呼んでいます。
なお、DELETE 文の WHERE 句では、サブクエリーを記述することもできます。このサブ
クエリーでは、複数のテーブルを指定することもできます。サブクエリーの詳細は、6-51
ページの「サブクエリー」を参照してください。
複数行の削除
複数行を削除する方法には、基本的に次の 2 種類があります。
• 検索削除:この方法では、検索条件に該当する行がすべて削除されます。複数行を自動削
除するときに有効です。
• 位置指定削除:カーソルを使って行を取り出し、1 行ごとに削除を行う方法です。ユーザー
による削除を扱う場合に有効な方法で、行を取り出し、ユーザーの許可があれば削除され
るように記述します。
位置指定削除よりも検索削除の方がプログラミングは簡単ですが、位置指定削除の方が処
理の点で柔軟です。
検索削除の記述
検索削除では、WHERE 句で記述されている検索条件に合致する行を一括して削除すること
ができます。たとえば、次は、ユーザーに国名の入力を求め、入力された国に属する都市を
一括して削除する場合の C のコード例です。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char country[26];
EXEC SQL
END DECLARE SECTION;
. . .
main ()
6-66 埋 め 込 み S Q L ガ イ ド
データの削除
{
printf("Enter country with cities to delete: ");
gets(country);
EXEC SQL
DELETE FROM CITIES
WHERE COUNTRY = :country;
if(SQLCODE && (SQLCODE != 100))
{
isc_print_sqlerr(SQLCODE, isc_status);
EXEC SQL
ROLLBACK RELEASE;
}
else
{
EXEC SQL
COMMIT RELEASE;
}
}
位置指定削除の記述
カーソルを使って行を選択して削除を行う方法を位置指定削除と言います。この削除では、
1 行ごとにユーザーによる削除の許可を求めます。また、削除前の値と削除後の値を表示し
ます。位置指定削除は、次の 7 つの手順で行われます。
1
2
削除処理で必要になる変数を宣言します。
3
4
5
6
カーソルを開きます。
7
上のステップ 3 ~ 6 の処理を繰り返し、取り出し対象となっている行をすべて削除しま
す。
カーソルを宣言します。このカーソルは、削除の対象となる行の取り出しに使用しま
す。また、FOR UPDATE 句を記述します。カーソルの宣言と使い方の詳細は、6-35
ページの「複数行の取り出し」を参照してください。
行を取り出します。
現在値が表示され、削除の許可が求められます。
WHERE CURRENT OF 句を使用して、現在取り出されている行を削除します。WHERE
CURRENT OF 句ではカーソル名を指定します。
たとえば、次は、CITIES テーブルに格納されている行のうち、北アメリカにある都市の行
を取り出し、ユーザーが Y を入力すれば削除を実行するという内容の C のコード例です。
. . .
EXEC SQL
BEGIN DECLARE SECTION;
char cityname[26];
EXEC SQL
第 6 章 データ処理
6-67
データの削除
END DECLARE SECTION;
char response[5];
. . .
main ()
{
EXEC SQL
DECLARE DELETECITY CURSOR FOR
SELECT CITY,
FROM CITIES
WHERE CONTINENT = 'North America';
EXEC SQL
OPEN DELETECITY;
while (!SQLCODE)
{
EXEC SQL
FETCH DELETECITY INTO :cityname;
if (SQLCODE)
{
if (SQLCODE == 100)
{
printf('Deletions complete.');
EXEC SQL
COMMIT;
EXEC SQL
CLOSE DELETECITY;
EXEC SQL
DISCONNECT ALL:
}
isc_print_sqlerr(SQLCODE, isc_status);
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT ALL;
exit(1);
}
printf("¥nDelete %s (Y/N)?", cityname);
gets(response);
if(response[0] == 'Y' || response == 'y')
{
EXEC SQL
DELETE FROM CITIES
WHERE CURRENT OF DELETECITY;
if(SQLCODE && (SQLCODE != 100))
{
isc_print_sqlerr(SQLCODE, isc_status);
6-68 埋 め 込 み S Q L ガ イ ド
データの削除
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT;
exit(1);
}
}
}
ビューを使った削除
既存の行はビューを介して削除することもできます。ただし、次の条件が必要です。
• ビューが更新可能であること。更新可能なビューの詳細は、
『データ定義ガイド』を参照
してください。
• 使用するビューの DELETE 特権がユーザーに与えられていること。ストアドプロシージャ
の場合は、そのストアドプロシージャに対して、使用するビューの DELETE 特権が与えら
れていること
たとえば、DEPARTMENT テーブルの行のうち、BUDGET 列の値(予算)が 1000000 ドル
未満の行を PART_DEPT ビューを使ってすべて削除する場合、DELETE 文は次のようになり
ます。
EXEC SQL
DELETE FROM PART_DEPT
WHERE BUDGET < 1000000;
ビューの作成の詳細は、第 5 章「データ定義文」を参照してください。CREATE VIEW 構
文の詳細は、『言語リファレンス』を参照してください。
メモ
トリガーを使用して、更新不可のビューを削除する方法についてのヒントは、
『データ定義
ガイド』を参照してください。
DELETE でのトランザクション名の指定
InterBase では、SQL アプリケーションが複数のトランザクションを同時に実行できます。
ただし、次の条件が必要です。
• トランザクションがそれぞれ SET TRANSACTION 文で事前に宣言されていること。
トラン
ザクション処理と命名の詳細は、第 4 章「トランザクションの操作」を参照してください。
• データ操作文(SELECT、INSERT、UPDATE、DELETE、DECLARE、OPEN、FETCH、CLOSE)
で TRANSACTION 句が使用されており、関連するトランザクションが指定されているこ
と。
• SQL 文が DSQL ではないこと。DSQL では、ユーザーがトランザクション名を定義すること
はできません。
上記のように、TRANSACTION 句でトランザクション名を指定することによって、DELETE
文で任意のトランザクションを使った削除が可能になります。この場合、構文は次のよう
になります。
第 6 章 データ処理
6-69
DELETE TRANSACTION name FROM table ...
なお、最初から最後まで 1 つのトランザクションしか使用しないプログラム、または一度
に 1 つのトランザクションしか起動しないプログラムでは、TRANSACTION 句は記述しな
くてもかまいません。つまり、TRANSACTION 句は、同時に複数のトランザクションを使
用するプログラムに限って必要になります。たとえば、次の DELETE 文は、T1 というトラ
ンザクションとともに機能します。
EXEC SQL
DELETE TRANSACTION T1 FROM PART_DEPT
WHERE BUDGET < 1000000;
6-70 埋 め 込 み S Q L ガ イ ド
第
章
日付と時刻
第7章
ホスト言語の多くは、DATE 、TIME、TIMESTAMP データ型をサポートしておらず、文字列
または構造体として扱っています。InterBase では、DATE と TIME データ型は 1 つの long 整
数として、TIMESTAMP データ型は 2 つの long 整数としてデータベースに格納されます。
InterBase の DATE データ型には日付(年、月、日)の情報、TIME データ型には時刻の情
報、TIMESTAMP データ型には日付と時刻の両方の情報が格納されます。
この章では、SQL アプリケーションでテーブルの日付と時刻のデータに対して SELECT、
INSERT、UPDATE を使用する方法について説明します。このような操作には、以下の isc
呼び出しインターフェースルーチンを使用します。
• isc_decode_sql_date() は、InterBase の内部日付形式を C の時刻構造体(struc tm)に変換します。
• isc_encode_sql_date() は、C の時刻構造体を InterBase の内部日付形式に変換します。
• isc_decode_sql_time() は、InterBase の内部時刻形式を C の時刻構造体に変換します。
• isc_encode_sql_time() は、C の時刻構造体を InterBase の内部時刻形式に変換します。
• isc_decode_timestamp() は、InterBase の内部タイムスタンプ形式を C の時刻構造体に変換しま
す。これは、以前は isc_decode_date() が行っていました。
• isc_encode_timestamp() は、C の時刻構造体を InterBase の内部タイムスタンプ形式に変換しま
す。これは、以前は isc_encode_date() が行っていました。
各関数の説明は、『API ガイド』を参照してください。
この章ではまた、CAST() 関数の使い方についても説明します。この CAST() 関数では、
DATE、TIME、TIMESTAMP データ型の相互の変換、および CHAR データ型との相互の変
換が可能です。また、日付リテラル(YESTERDAY、TOMORROW、NOW、TODAY)によ
る日付の選択と挿入についても紹介します。
第 7 章 日付と時刻
7-1
現在の日付と時刻の情報をデータベースに問い合わせる
現在の日付と時刻の情報をデータベースに問い合わせる
InterBase は、現在の日付および時刻値を取得するための定義済み SQL 関数演算子と、日付
値または時刻値を個別に取得するための EXTRACT() 関数を提供しています。
現在の日付と時刻の取得
CURRENT_DATE、CURRENT_TIME、および CURRENT_TIMESTAMP 関数演算子は、サー
バーのクロックと時間帯を使用して、SQL 文が実行された時点の日付と時刻の値を返します。
単一の
SQL
文では、その文内の
CURRENT_DATE、CURRENT_TIME、および
CURRENT_TIMESTAMP には同じ値が使用されます。これは、次の文のように複数の行が更新
される場合に、各データ行の aTime 列が同じ値になることを意味します。
UPDATE aTable SET aTime = CURRENT_TIME;
同様に、リモートプロトコルを通した取り出しで行のバッファリングが発生した場合、
CURRENT_TIME はデータベースエンジンからカーソルを OPEN した時刻に基づき、クラ
イアントに到着した時刻には基づきません。
ドメインまたは列の定義のデフォルトの句として、CURRENT_DATE、CURRENT_TIME、
または CURRENT_TIMESTAMP を指定できます。
日付時刻情報の取り出し
EXTRACT() 関数は、データベースから日付および時刻情報を取り出します。EXTRACT() の
構文は次のとおりです。
EXTRACT (part FROM value)
EXTRACT() 式に渡される値は、DATE、TIME、または TIMESTAMP でなければなりません。
データ型の中に存在しない部分を取り出そうとすると、エラーになります。例を示します。
EXTRACT (TIME FROM aTime)
これは正しく動作しますが、
EXTRACT (YEAR from aTIME)
これはエラーになります。
EXTRACT() 式のデータ型は、取り出される部分によって決まります。
表 7.1
日付時刻情報の取り出し
取り出す部分
結果のデータ型
表す内容
YEAR
SMALLINT
年(0 ~ 5400)
MONTH
SMALLINT
月(0 ~ 12)
DAY
SMALLINT
日(1 ~ 31)
HOUR
SMALLINT
時(0 ~ 23)
MINUTE
SMALLINT
分(0 ~ 59)
7-2 埋 め 込 み S Q L ガ イ ド
日付と時刻の取り出し
表 7.1
日付時刻情報の取り出し
取り出す部分
結果のデータ型
表す内容
SECOND
DECIMAL(6,4)
秒(0 ~ 59.9999)
WEEKDAY
SMALLINT
曜日(0 ~ 6。
0 = 日曜、1 = 月曜、...)
YEARDAY
SMALLINT
年初からの日数(1 ~ 366)
日付と時刻の取り出し
日付と時刻(タイムスタンプ)を取り出して C 言語プログラムで使用可能な形式に変換す
る手順は次のとおりです。
1
C の時刻構造体を表すホスト言語変数を作成します。ほとんどの C / C++ コンパイラで
は、C の時刻構造体は time.h ヘッダーファイルで tm 構造体型として typedef 宣言されて
います。次の C コードは、time.h をインクルードして、tm 構造体型の変数を宣言してい
ます。
#include <time.h>;
. . .
struct tm hire_time;
. . .
C/C++ 以外の言語では、時刻構造体の作成方法が上記とは異なります。詳細は、使用
する言語のリファレンスマニュアルを参照してください。
2
ISC_TIMESTAMP 型の変数を宣言します。たとえば、記述は次のようになります。
ISC_TIMESTAMP hire_date;
ISC_TIMESTAMP 構造体は、gpre で前処理を行ったときに自動的に宣言されますが、プ
ログラムの記述の際は、実際に使用する ISC_TIMESTAMP 型の変数はプログラムで宣言
しなければなりません。
3
テーブルから ISC_TIMESTAMP 変数にタイムスタンプを取り出します。次に例を示しま
す。
EXEC SQL
SELECT LAST_NAME, FIRST_NAME, DATE_OF_HIRE
INTO :lname, :fname, :hire_date
FROM EMPLOYEE
WHERE LAST_NAME = 'Smith' AND FIRST_NAME = 'Margaret';
この後、InterBase の isc_decode_timestamp() 関数を使用して、変数 hire_date のデータを C
プログラムで使用可能な形式に変換します。なお、この関数は、gpre による前処理の際
に自動的に宣言されます。isc_decode_timestamp() 関数では、ISC_TIMESTAMP 型の変数
(変換元)と tm 構造体型の変数(変換先)の 2 つのパラメータを順に指定します。たと
えば、次の例は、hire_date を hire_time に変換する場合の記述です。
isc_decode_timestamp(&hire_date, &hire_time);
第 7 章 日付と時刻
7-3
入力のための日付の書式
入力のための日付の書式
DATE データ型として入力される日付は、以下の書式を設定できます。
• YYYYpMMpDD
• MMpDDpYYYY
• DDpMMpYYYY
• YYpMMpDD
• MMpDDpYY
• DDpMMpYY
ここで
• DD = 1 桁または 2 桁の日
• MM = 1 桁または 2 桁の月、または 3 文字の月の省略名、または英語の完全な月名(大文字
と小文字の区別はなし)
• YY = 年の下 2 桁
• YYYY = 4 桁の年
• p = ASCII 区切り文字。余分な空白(タブまたはスペース)は無視される
以下の制限が適用されます。
• 「年 - 月 - 日」形式では、年は常に 4 桁でなければならない
• 「月 - 日 - 年」形式では、年は 2 桁または 4 桁。年を 2 桁で入力した場合、InterBase は
「スライドウィンドウ」アルゴリズムを使用して、年に世紀を割り当てます。詳細は、
string_to_datetime() ルーチンの説明を参照してください。
• ピリオドを区切りにし、年が最後に来るすべて数字の形式を使用した場合、InterBase はそ
の形式が「日 - 月 - 年」であると解釈します。たとえば、‘12.04.2002’ は、‘December 4, 2002’ で
はなく、“April 12, 2002,” と解釈されます。
InterBase エンジンの string_to_datetime() ルーチンからの抜粋:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
String must be formed using ASCII characters only.
Conversion routine can handle the following input formats
“now” current date and time
“today”
Today’s date 0:0:0.0 time
“tomorrow” Tomorrow’s date0:0:0.0 time
“Yesterday”Yesterday’s date0:0:0.0 time
YYYY-MM-DD [HH:[Min:[SS.[Thou]]]]]
MM:DD[:YY [HH:[Min:[SS.[Thou]]]]]
DD:MM[:YY [HH:[Min:[SS.[Thou]]]]]
Where:
DD = 1..31(Day of month)
YY = 00..99 2-digit years are converted to the nearest year
in a 50-year range. Eg: if this is 1996:
96 ==> 1996
7-4 埋 め 込 み S Q L ガ イ ド
日付と時刻の挿入
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
97 ==> 1997
...
00 ==> 2000
01 ==> 2001
...
44 ==> 2044
45 ==> 2045
46 ==> 1946
47 ==> 1947
...
95 ==> 1995
If the current year is 1997, then 46 is converted
to 2046 (etc.)
= 100.. 5200
MM = 1 .. 12 (Month of year)
= “JANUARY”...(etc.)
HH = 0...23 (Hour of day)
Min = 0...59 (Minute of hour)
SS = 0...59 (Second of minute - LEAP second not supported)
Thou = 0...9999 (Fraction of second)
HH, Min, SS, Thou default to 0 if missing.
YY defaults to current year if missing.
Note: ANY punctuation can be used instead of : (eg: / - etc)
Using .(period) in either of the first two separation
points will cause the date to be parsed in European DMY
format.
Arbitrary whitespace (space or TAB) can occur between
components.
日付と時刻の挿入
テーブルに日付と時刻(タイムスタンプ)を挿入する場合、日付をホスト言語の形式から
InterBase の形式に変換する必要があります。C 言語のプログラムでの日付の変換および
テーブルへの挿入は、次の手順で行います。
1
C 言語の時刻構造体を表す変数を作成します。通常、C または C++ のコンパイラでは、
C の時刻構造体は time.h ヘッダーファイルで tm 構造体型として typedef 宣言されていま
す。次の C コードは、time.h をインクルードし、tm 構造体型の変数 hire_time を宣言して
います。
#include <time.h>;
. . .
struct tm hire_time;
. . .
C/C++ 以外の言語では、時刻構造体の作成方法が上記とは異なります。詳細は、使用
する言語のリファレンスマニュアルを参照してください。
第 7 章 日付と時刻
7-5
日付と時刻の更新
2
InterBase が使用する ISC_TIMESTAMP 型のホスト変数を宣言します。ホスト変数の宣言
は、たとえば、次のようになります。
ISC_TIMESTAMP mydate;
ISC_TIMESTAMP 構造体は、gpre で前処理を行ったときに自動的に宣言されますが、プ
ログラムの記述の際は、実際に使用する ISC_TIMESTAMP 型の変数はプログラムで宣言
しなければなりません。
3 日付情報を hire_time に格納します。
4 InterBase の isc_encode_timestamp() 関数を使用して、変数 hire_time のデータを InterBase
の内部形式に変換するとともに、データを ISC_TIMESTAMP 型の変数(ここでは
hire_date)に格納します。この関数は、gpre による前処理の際に自動的に宣言されます。
isc_encode_timestamp() 関数では、tm 型の変数(変換元)と ISC_TIMESTAMP 型の変数
(変換先)の 2 つのパラメータを順に指定します。
たとえば、次のコードは、hire_time を hire_date に変換します。
isc_encode_timestamp(&hire_time, &hire_date);
5
日付をテーブルに挿入します。次に例を示します。
EXEC SQL
INSERT INTO EMPLOYEE (EMP_NO, DEPARTMENT, DATE_OF_HIRE)
VALUES (:emp_no, :deptname, :hire_date);
日付と時刻の更新
テーブルの DATE、TIME、または TIMESTAMP データ型を更新するには、ホスト言語の形
式を InterBase の形式に変換してから格納します。ホスト変数を InterBase 形式に変換する
方法は、7-4 ページの「入力のための日付の書式」を参照してください。実際の更新は、
UPDATE 文を使って行います。次に例を示します。
EXEC SQL
UPDATE EMPLOYEE
SET DATE_OF_HIRE = :hire_date
WHERE DATE_OF_HIRE < '1 JAN 1994'
CAST() による日付と時刻の変換
SELECT 文で組み込みの CAST() 関数を使用すると、日付および時刻データ型と、文字ベー
スのデータ型の間で以下の変換を行うことができます。
• DATE、TIME、TIMESTAMP データ型から CHAR データ型へ
文字データ型は、少なくとも 24 文字の長さが必要です。ただし、TIMESTAMP を DATE に
キャストすれば、その DATE は 24 文字より短い CHAR にキャストできます。次に例を示し
ます。
SELECT CAST (CAST (timestamp_col AS DATE) AS CHAR(10)) FROM table1;
• CHAR データ型から DATE、TIME、TIMESTAMP データ型へ
7-6 埋 め 込 み S Q L ガ イ ド
CAST() による日付と時刻の変換
• DATE、TIME データ型から TIMESTAMP データ型へ
• TIMESTAMP データ型から DATE、TIME データ型へ
日付または時刻データ型は、BLOB、SMALLINT、INTEGER、FLOAT、DOUBLE PRECISION、
NUMERIC、および DECIMAL データ型との間でキャストすることはできません。
通常、CAST() は WHERE 句で異なるデータ型を比較するために使用します。CAST() の構文
は次のとおりです。
CAST (<value> AS <datatype>)
次の WHERE 句では、CAST() を使って CHAR データ型である INTERVIEW_DATE のデータ
を DATE データ型に変換し、その後、DATE データ型である HIRE_DATE のデータと比較し
ています。
… WHERE HIRE_DATE = CAST(INTERVIEW_DATE AS DATE);
次の例では、CAST() で DATE データ型を CHAR データ型に変換しています。
… WHERE CAST(HIRE_DATE AS CHAR) = INTERVIEW_DATE;
CAST() を使用することで、同じテーブルにデータ型の異なる列があっても比較が可能で
す。また、CAST() は、別のテーブルの列に対しても使用できます。
次の 2 つのセクションでは、日付時刻データ型(DATE、TIME、TIMESTAMP)と他の SQL
データ型との間で行うことができる変換について説明します。
CAST() の詳細は、第 6 章「データ処理」を参照してください。
SQL データ型から日付時刻データ型へのキャスト
次の表は、DATE、TIME、TIMESTAMP データ型にキャストできる SQL データ型を示して
います。
表 7.2
SQL データ型から日付時刻データ型へのキャスト
キャスト先
キャスト元
TIMESTAMP
DATE
TIME
SMALLINT
INTEGER
FLOAT
DOUBLE PRECISION
NUMERIC
DECIMAL
エラー
エラー
エラー
VARCHAR(n)
CHAR(n)
CSTRING(n)
文字列が次の形式の場合、 文字列が次の形式の場合、 文字列が次の形式の場合、
キャスト可。
キャスト可。
キャスト可。
BLOB
YYYY-MM-DD
HH:MM:SS.thou
YYYY-MM-DD
HH:MM:SS.thou
エラー
エラー
エラー
第 7 章 日付と時刻
7-7
CAST() による日付と時刻の変換
表 7.2
SQL データ型から日付時刻データ型へのキャスト ( 続き )
キャスト先
キャスト元
TIMESTAMP
DATE
TIME
TIMESTAMP
常にキャスト可
キャスト可。 TIMESTAMP
の日付部分
キャスト可。TIMESTAMP
の時刻部分
DATE
キャスト可。
TIMESTAMP
の時刻部分は 0:0:0.0000 に
設定される
常にキャスト可
エラー
TIME
キャスト可。
TIMESTAMP
の日付部分は起算日付
(1858 年 11 月 17 日)に設定
される
エラー
常にキャスト可
日付時刻データ型から他の SQL データ型へのキャスト
次の表は、DATE、TIME、TIMESTAMP データ型からキャストできる SQL データ型を示し
ています。
表 7.3
日付時刻データ型から他の SQL データ型へのキャスト
キャスト元
キャスト先
TIMESTAMP
DATE
TIME
SMALLINT
INTEGER
FLOAT
DOUBLE PRECISION
NUMERIC
DECIMAL
エラー
エラー
エラー
VARCHAR(n)
CHAR(n)
CSTRING(n)
n が 24 文字以上の場合は
キャスト可。結果の文字列
は次の形式になる。
n が 10 文字以上の場合は
キャスト可。結果の文字列は
次の形式になる。
n が 10 文字以上の場合は
YYYY-MM-DD
HH:MM:SS.thou
YYYY-MM-DD
HH:MM:SS.thou
BLOB
エラー
エラー
エラー
TIMESTAMP
常にキャスト可
キ ャ ス ト 可。時 刻 部 分 は
0:0:0.0000 に設定される
キャスト可。
日付部分は 1858
年 11 月 17 日に設定される
DATE
キャスト可。
TIMESTAMP
の日付部分が結果になる
常にキャスト可
エラー
TIME
キャスト可。
TIMESTAMP
の時刻部分が結果になる
エラー
常にキャスト可
キャスト可。結果の文字列は
次の形式になる。
DATE を文字列にキャストすると "YYYY-MM-DD" の形式(“MM” は 2 桁の月)になります。
結果が文字列変数のサイズでは収まらない場合、文字列切り詰めの例外が生成されます。
文字列を日付にキャストする場合、文字列は次の形式でなければなりません。
‘yyy-mm-dd’‘yyyy/mm/dd’‘yyyy mm dd
7-8 埋 め 込 み S Q L ガ イ ド
日付リテラルの使い方
‘yyyy:mm:dd’‘yyyy.mm.dd’
この 4 つの形式では、月(mm)は完全な月名または 3 文字の省略名に置き換えることがで
きます。ただし、順序は 4 桁の年、月、日の順でなければなりません。
また、次の形式も使用できます。
‘mm-dd-yy’ ‘mm-dd-yyyy’‘mm/dd/yy’‘mm/dd/yyyy’
‘mm dd yy’ ‘mm dd yyyy’‘mm:dd:yy’‘mm:dd:yyyy’
‘dd.mm.yy’ ‘dd.mm.yyyy’
年が 2 桁の日付を入力した場合、InterBase は「スライドウィンドウ」アルゴリズムを使っ
て年に世紀を割り当てます。
月を英語の完全な名前または英語の 3 文字の省略名で指定する場合、月と日はどちらが先
でもかまいません。以下の例では、“xxx” は完全な月名または 3 文字の省略名を表します。
以下のすべての形式を使用できます。
‘dd-xxx-yy’‘dd-xxx-yyyy’‘xxx-dd-yy’‘xxx-dd-yyyy’
‘dd xxx yy’‘dd xxx yyyy’‘xxx dd yy’‘xxx dd yyyy’
‘dd:xxx:yy’‘dd:xxx:yyyy’‘xxx:dd:yy’‘xxx:dd:yyyy’
たとえば、以下の INSERT 文はどれも 1943 年 1 月 22 日の日付を挿入します。
INSERT
INSERT
INSERT
INSERT
INTO
INTO
INTO
INTO
t1
t1
t1
t1
VALUES
VALUES
VALUES
VALUES
(‘1943-01-22’);
(‘01/22/1943’);
(‘22.01.1943’);
(‘jan 22 1943’);
次の文は、2043 年 1 月 22 日の日付を挿入します。
INSERT INTO t1 VALUES (‘01/22/43’);
日付リテラルの使い方
InterBase では、'NOW'、‘TODAY’、'YESTERDAY'、および 'TOMORROW' の 4 つの日付リテ
ラルを使用できます。日付リテラルは引用符で囲まれた文字列値で、その値は EXTRACT、
SELECT、INSERT、および UPDATE で日付として解釈されます。'TIMESTAMP' は、その時
点の日付と時刻を InterBase 形式で表す日付リテラルです。'DATE' は、当日の日付情報を表
し、時刻は 0 です。同じように、'YESTERDAY' と 'TOMORROW' は名前どおりの日付を表
し、時刻は 0 です。
EXTRACT と SELECT では、'TODAY' と 'NOW' を WHERE 句の検索条件で使用することで、
取り出すデータの絞り込みが可能になります。例を示します。
EXEC SQL
SELECT * FROM CROSS_RATE WHERE UPDATE_DATE = 'NOW';
INSERT ま た は UPDATE で 'TODAY' と 'NOW' を使用すれば、isc 呼び出しで C 形式を
InterBase 形式に変換しなくても、日付時刻情報を入力することができます。
EXEC SQL
INSERT INTO CROSS_RATE VALUES(:from, :to, :rate, 'NOW');
EXEC SQL
UPDATE CROSS_RATE
第 7 章 日付と時刻
7-9
日付および時刻データ型の加算と減算
SET CONV_RATE = 1.75,
SET UPDATE_DATE = 'TODAY'
WHERE FROM_CURRENCY = 'POUND' AND TO_CURRENCT = 'DOLLAR'
AND UPDATE_DATE < 'TODAY';
日付および時刻データ型の加算と減算
次の表に、DATE、TIME、TIMESTAMP、および数値データ型の加算と減算の結果を示しま
す。「数値」は、データベースエンジンによって高精度数値にキャストが可能なすべての型
(INTEGER、DECIMAL、NUMERIC など)を表します。
表 7.4
日付 / 時刻データ型の加算と減算
Operand1
演算子
Operand2
結果
DATE
+
DATE
エラー
DATE
+
TIME
TIMESTAMP(連結)
DATE
+
TIMESTAMP
エラー
DATE
+
数値
DATE + 日数(小数部は無視される)
TIME
+
DATE
TIMESTAMP(連結)
TIME
+
TIME
エラー
TIME
+
TIMESTAMP
エラー
TIME
+
数値
TIME + 秒数(24 時間の剰余演算)
TIMESTAMP
+
DATE
エラー
TIMESTAMP
+
TIME
エラー
TIMESTAMP
+
TIMESTAMP
エラー
TIMESTAMP
+
数値
TIMESTAMP(DATE + 日数)
TIME + 数値の小数部を秒数に変換した値
DATE
-
DATE
DECIMAL(9,0)(日数を表す)
DATE
-
TIME
エラー
DATE
-
TIMESTAMP
エラー
DATE
-
数値
DATE= 日数(小数部は無視される)
TIME
-
DATE
エラー
TIME
-
TIME
DECIMAL(9,4)(秒数を表す)
TIME
-
TIMESTAMP
エラー
TIME
-
数値
TIME - 秒数 (24 時間の剰余演算)
TIMESTAMP
-
DATE
エラー
7-10 埋 め 込 み S Q L ガ イ ド
日付と時刻の比較
表 7.4
日付 / 時刻データ型の加算と減算 ( 続き )
Operand1
演算子
Operand2
結果
TIMESTAMP
-
TIME
エラー
TIMESTAMP
-
TIMESTAMP
DECIMAL(18,9)(整数部が日数、小数部が秒数を表す)
TIMESTAMP
-
数値
TIMESTAMP:DATE - 日数、および TIME - 数値の小数
部を秒数に変換した値
日付と時刻の比較
日付および時刻値は、暗黙的に変換される場合があります。次の比較を見てください。
Table1.SomeDateField <= ‘12/31/1999’
InterBase は、比較演算が行われる場合、文字列リテラル ‘12/31/1999’ を自動的に DATE
に変換します。
ただし、式がそのままで意味を持つ場合は、暗黙の変換は必ずしも行われません。次に例
を示します。
‘31.5.2000’ < ‘1.6.2000’
この 2 つの文字列のアルファベット順の比較は偽になるため、この式は常に偽になります。
i この 2 つの値の文字列比較は有効なので、これらが「日付のように」見えても、日付への
暗黙の変換は行われません。一方、次の比較を見てください。
CAST(‘31.5.2000’ AS DATE) < CAST(‘1.6.2000’ AS DATE)
これらの文字列に対応する日付を比較した結果は真なので、この式は真になります。詳細
は、『データ定義ガイド』の「暗黙の型変換」を参照してください。
日付および時刻データ型を集計関数で使用する
日 付 お よ び 時 刻 デ ー タ 型 は、MIN()、MAX()、COUNT() 関数、およびこれらの関数の
DISTINCT 引数、また SELECT() 関数の GROUP BY 引数に使用できます。日付および時刻
データ型を SUM() および AVG() 関数で使用するとエラーが返されます。
第 7 章 日付と時刻
7-11
7-12 埋 め 込 み S Q L ガ イ ド
第
第8章
章
BLOB データの操作
この章では、BLOB データ型とそのサブタイプ、BLOB の格納方法、SQL、DSQL、および
API 呼び出しを使って BLOB にアクセスする方法、BLOB のフィルタリングについて説明し
ます。また、BLOB フィルタの記述方法についても説明します。
BLOB の概要
BLOB とは、動的にサイズを決定できるデータ型を指します。この BLOB データでは、サイ
ズおよびコード化形式は指定されません。BLOB を使用すると、さまざまな型の大容量デー
タを格納できます。種類としては主に以下の 4 つがあります。
• ビットマップイメージ
• ベクタードローイング
• サウンド、ビデオセグメント(ビデオクリップ)
、およびその他のマルチメディア情報
• テキスト(文字データ)
BLOB データ型で格納されたデータは、他のデータベースに格納されているデータとほとん
ど同じように操作できます。また、InterBase では、BLOB データはデータベースに直接格納さ
れます。これに対して、一般のシステムでは、データベースにはポインタだけが置かれ、実
際のファイルはデータベースの外部に配置されるのが一般的です。InterBase には、さらに識
別ハンドルを記述したテーブルがあり、この識別ハンドルによってデータベース中の BLOB
データの位置が示されます。このほか、BLOB データがデータベースに直接格納されているこ
とから、データへのアクセス、データの管理の両面で動作が大幅に向上します。
以上のように、各種の BLOB データ型をサポートしていることに加えて、BLOB データに対
する管理能力も優れているため、InterBase は、トランザクション中心型のマルチメディア
アプリケーションの作成にも適しています。たとえば、対話形式のキオスク型のアプリケー
ションの作成には理想的で、数百、数千の製品について、説明や写真、ビデオクリップを
盛り込むことができます。また、これらのアプリケーションに、POS システムや受発注シ
ステムを組み込むこともできます。
第 8 章 BLOB データの操作
8-1
BLOB データの格納方法
BLOB データの格納方法
BLOB データは、種類としてはビットマップイメージ、サウンド、ビデオ、テキストの 4 つ
に分かれます。ただし、この 4 つは内容から見た場合の種類で、データベースへの BLOB
データの格納に先立ち、現在使用しているプラットフォームやシステムに対応したファイ
ル形式で BLOB データを用意しておかなければなりません。この場合のファイルとしては、
次のようなものがあります。
• TIFF、PICT、.BMP、.WMF、.GEM、TARGA などのビットマップまたはベクターグラフィッ
クファイル
• MIDI または .WAV のサウンドファイル
• Video for Windows のファイル(.AVI)や QuickTime ムービーのファイル(.MOV)
• ASCII、.MIF、.DOC、.WPx などのテキストファイル
• CAD ファイル
上記の各種ファイルは、プログラムを使ってメモリからデータベースにロードしなければ
なりません。処理の手順は、ホスト言語のデータやレコードを InterBase に格納する場合と
同じです。
BLOB サブタイプ
BLOB データの扱い方は、InterBase の他のデータ型のデータの場合と同じです。ただし、
BLOB データの場合、データ型の検査はそれほど厳密には行われません。これは、BLOB デー
タとしてユーザーが定義できるデータ型が非常に多いためです。ユーザーはデータ型の検
査がゆるやかな分だけ、自由にデータ型を定義することができます。このユーザー定義の
BLOB データ型を BLOB のサブタイプと呼んでいます。また、ユーザー定義のサブタイプと
は別に、標準のサブタイプが事前に用意されています。InterBase で用意されている標準サ
ブタイプは次の 7 つです。
表 8.1
InterBase で定義されている BLOB サブタイプ
BLOB
サブタイプ
説明
0
構造を持たないバイナリデータ一般、または型が未決定のデータに適用される
1
テキスト
2
バイナリ言語表現(BLR)
3
アクセス制御リスト
4
(予約)
5
テーブルの現在のメタデータの符号化記述
6
正常に終了しなかったマルチデータベーストランザクションの記述
ユーザー定義のサブタイプは、–1 ~ –32768 までの負の数値として指定します。正の数値は
InterBase で予約されているため、ユーザー定義のサブタイプには使用できません。
8-2 埋 め 込 み S Q L ガ イ ド
BLOB データの格納方法
たとえば、次の文は、テーブルの作成の際に、3 つの BLOB 列を定義します。つまり、BLOB1
というサブタイプ 0(デフォルト)の BLOB 列、BLOB2 というサブタイプ 1(TEXT)の BLOB
列、BLOB3 というサブタイプ –1(ユーザー定義)の BLOB 列を定義します。
EXEC SQL
(
BLOB1
BLOB2
BLOB3
);
CREATE TABLE TABLE2
BLOB,
BLOB SUB_TYPE 1,
BLOB SUB_TYPE -1
また、BLOB 定義の際は、サブタイプと同時にデフォルトのセグメント長を定義することも
できます。セグメント長を定義するときは、SUB_TYPE の右に SEGMENT SIZE と長さ(バ
イト数)を記述します。次に例を示します。
EXEC SQL CREATE TABLE TABLE2
(
BLOB1 BLOB SUB_TYPE 1 SEGMENT SIZE 100;
);
なお、ユーザー定義のサブタイプは BLOB フィルタを使って別のユーザー定義のサブタイ
プに変換できますが、この場合、双方のサブタイプに互換性がなければなりません。互換性
のない場合は、サブタイプの整合性は保証されません。
BLOB のデータベース上での格納形式
BLOB データは、バイナリまたはテキストで構成されるかなり大きなオブジェクトで、サイ
ズも可変です。このため、InterBase では、BLOB データはセグメントという方法を使って
効率よく格納されます。つまり、1 つの BLOB データは大容量データのかたまりなので、こ
のかたまりを 1 つとして格納した場合は、ディスク容量の効率的利用という点では不利に
なります。この点を考慮して、InterBase では、BLOB データは複数のセグメントという形
で格納され、BLOB の作成の際はハンドルを使ってインデックスが作成されます。このハン
ドルを BLOB ID と呼びます。この BLOB ID は 4 ワード(64 ビット)の長さで、ここには、
テーブルの識別子と BLOB の識別子が組み合わされた形で保持されます。BLOB ID は、重
複しないように BLOB セグメントごとに作成されます。
BLOB ID は、テーブルの所定のフィールドに格納されます。BLOB ID は BLOB データの先頭
を指すこともありますし、場合によっては、ポインタのページ(複数のポインタで構成さ
れる表)を指すこともあります。参照先がページの場合、ページの個々のポインタがそれ
ぞれ BLOB データを指すことになります。BLOB ID は、SELECT 文で BLOB ID を指定するこ
とで取り出すことができます。たとえば、記述は次のようになります。
EXEC SQL
DECLARE BLOBDESC CURSOR FOR
SELECT GUIDEBOOK
FROM TOURISM
WHERE STATE = 'CA';
BLOB 列は、CREATE TABLE を使用して、BLOB 以外のデータ型の列とともに作成します。
第 8 章 BLOB データの操作
8-3
BLOB データの格納方法
他のデータ型の列と併せて PROJ_DESC という BLOB 列を作成する場合、CREATE TABLE 文
の記述は次のようになります。ここでは、サブタイプのパラメータは 1 になっています。これ
は TEXT BLOB を指します。さらに、セグメント長としては 80 バイトが設定されています。
CREATE TABLE PROJECT
(
PROJ_ID PROJNO NOT NULL,
PROJ_NAME VARCHAR(20) NOT NULL UNIQUE,
PROJ_DESC BLOB SUB_TYPE 1 SEGMENT SIZE 80,
TEAM_LEADER EMPNO,
PRODUCT PRODTYPE,
...
);
次の図は、BLOB ID を格納している BLOB 列と、その BLOB ID により参照される BLOB デー
タとの関係を示したものです。
図 8.1
データベース中の BLOB ID と BLOB セグメントとの関連
Blob
列
…
テーブル行
BLOB ID
BLOB データ
…
セグメント セグメント セグメント
…
このように、InterBase では、テーブルの行に BLOB ID が置かれています。直接 BLOB デー
タがテーブルに格納されるわけではありません。つまり、BLOB ID は BLOB データの最初の
セグメントを指すポインタで、実際の BLOB データはデータベースの別の場所にセグメン
トの連続という形で格納されます。また、アプリケーションで BLOB の書き込みを行うとき
は、セグメントごとに書き込みを行うことになります。同じく、アプリケーションで BLOB
の読み取りを行う場合、その読み取りはセグメント単位で実行することになります。この場
合、BLOB データは一般に大きいため、アプリケーションコードでループを使って処理する
のが普通です。
BLOB のセグメント長
CREATE TABLE を使って BLOB 列を定義する場合、BLOB 定義文の列に書き込まれる BLOB
のセグメント長を指定します。セグメント長は、セグメントの最大バイト数を指定します。
これで、その列については、指定されたバイト数をセグメントの最大長として BLOB デー
タの書き込みと読み取りが行われることになります。なお、セグメントのデフォルトの長さ
は 80 バイトとなっています。たとえば、次の例は、セグメント長が 120 バイトの BLOB 列
を作成する場合です。
EXEC SQL CREATE TABLE TABLE2
(
Blob1 Blob SEGMENT SIZE 120;
);
8-4 埋 め 込 み S Q L ガ イ ド
SQL での BLOB データへのアクセス
テーブルの作成時にセグメント長を設定した場合(設定しないときはデフォルトの 80)、そ
のセグメント長にしたがって内部バッファの大きさが決められ、このバッファに BLOB
データのセグメントが書き込まれることになります。通常は、テーブルで設定されているセ
グメント長を超えるような書き込みは行わないようにします。この場合、バッファのオー
バーフローが発生してメモリの整合性が失われることがあります。
テーブルの作成時に設定した列のセグメント長は、BLOB データの処理に関する文では、変
数を使って指定します。これで、そのセグメントの長さを最大長として BLOB データの処
理が実行されます。たとえば、SELECT、INSERT、UPDATE の場合、変数で指定したセグメ
ントを単位として読み取りや書き込みが行われることになります。
たとえば、次は INSERT CURSOR 文の例です。ここでは、変数 segment_length を使ってセグ
メント長を指定しています。
EXEC SQL
INSERT CURSOR BCINS VALUES (:write_segment_buffer
INDICATOR :segment_length);
INSERT CURSOR の構文およびセグメント長の指定については、
『言語リファレンス』を参
照してください。
DECLARE CURSOR でのセグメント長の変更
DECLARE CURSOR 文では、オプションの MAXIMUM_SEGMENT を記述することにより、
テーブルの作成時に設定されている BLOB 列のセグメント長を変更することができます。
たとえば、次の BLOB INSERT カーソル宣言では、BLOB2 という BLOB 列に設定されている
セグメント長を 1024 バイトに拡大しています。
EXEC SQL
DECLARE BCINS CURSOR FOR INSERT Blob Blob2 INTO TABLE 2
MAXIMUM_SEGMENT 1024;
メモ
MAXIMUM_SEGMENT を使ってセグメント長を変更した場合、その変更は、
DECLARE CURSOR で宣言したカーソルに対してだけ有効です。したがって、ここで宣言した
カーソル以外のカーソルでは、テーブルの作成時に設定されたセグメントサイズがそのまま
使用されます。このようなカーソルに対して、個別に MAXIMUM_SEGMENT を使ってセグメ
ント長を変更できます。
上のようにしてセグメント長を変更したときでも、InterBase の動作効率が低下することは
ありません。そのため、状況によってセグメント長は任意に指定できます。セグメントの最
大長は 64KB(65,535 バイト)です。
SQL での BLOB データへのアクセス
InterBase では、SELECT、INSERT、UPDATE、DELETE を使用して、BLOB データの取り出
し、挿入、更新、削除が可能です。以降、こういった処理の手順をサンプルプログラムを
使って説明します。どのサンプルプログラムも、SQL での BLOB データ処理としては一般に
使用されるものです。
第 8 章 BLOB データの操作
8-5
SQL での BLOB データへのアクセス
BLOB データの取り出し
サンプルプログラムを例に、BLOB データを取り出す場合の手順を説明します。ここでは、
TOURISM テーブルの GUIDEBOOK 列から BLOB データを取り出します。
1
次のようにして変数を宣言します。それぞれ、BLOB ID、BLOB データ、STATE 列の
データ、セグメント長を格納するための変数です。
EXEC SQL
BEGIN DECLARE SECTION;
BASED ON TOURISM.GUIDEBOOK blob_id;
BASED ON TOURISM.GUIDEBOOK.SEGMENT blob_segment_buf;
BASED ON TOURISM.STATE state;
unsigned short blob_seg_len;
EXEC SQL
END DECLARE SECTION;
上の文で、BASED ON … SEGMENT 構文は、データが BLOB の場合に必要になります。
ここでは、変数 blob_segment_buf を宣言しています。FETCH の処理では、この変数に
BLOB データのセグメント(1 つ)が格納されることになります。BASED ON 文の詳細
は、『言語リファレンス』を参照してください。
2
BLOB 列のデータを取り出すためのカーソル(テーブルカーソル)を宣言します。ここ
では SELECT で GUIDEBOOK 列を指定します。なお、STATE 列も指定しています。
EXEC SQL
DECLARE TC CURSOR FOR
SELECT STATE, GUIDEBOOK
FROM TOURISM
WHERE STATE = 'CA';
3
BLOB データを読み取るためのカーソルを宣言します。これは、BLOB セグメントの読
み取りに使用する特殊なカーソルで、BLOB 読み取りカーソルと呼ばれています。
EXEC SQL
DECLARE BC CURSOR FOR
READ Blob GUIDEBOOK
FROM TOURISM;
なお、GUIDEBOOK BLOB 列のセグメント長は 60 に設定されているため、BLOB カーソ
ル BC では、最長 60 バイトの大きさで各セグメントが読み取られることになります。
GUIDEBOOK のデータベーススキーマで指定したセグメントの長さを上書きするには、
MAXIMUM_SEGMENT オプションを使用します。たとえば、次のコードは、Blob 読み
取り処理を最大 40 バイトに限定し、SQLCODE は 101 に設定されて、セグメントの一
部だけが読み取られていることを示します。
EXEC SQL
DECLARE BC CURSOR FOR
READ Blob GUIDEBOOK
FROM TOURISM
MAXIMUM_SEGMENT 40;
8-6 埋 め 込 み S Q L ガ イ ド
SQL での BLOB データへのアクセス
セグメント長を変更したときでも、セグメントは必ず 1 回に 1 つずつ、順に読み取られ
ます。
4
テーブルカーソルを開き、FETCH で BLOB データ(BLOB ID)を格納している行を取
り出します。
EXEC SQL
OPEN TC;
EXEC SQL
FETCH TC INTO :state, :blob_id;
上の FETCH 文により、STATE と GUIDEBOOK の 2 つの列のデータ(GUIDEBOOK の場
合は BLOB ID)が、それぞれ state と blob_id の 2 つの変数に格納されます。
5
変数 blob_id に格納されている BLOB ID を使用して、BLOB 読み取りカーソル(BC)を
開くとともに、BLOB データの最初のセグメントを取り出します。
EXEC SQL
OPEN BC USING :blob_id;
EXEC SQL
FETCH BC INTO :blob_segment_buf:blob_seg_len;
前の文では、FETCH が実行されると同時に、BLOB データの最初のセグメントが変数
blob_segment_buf に格納されます。この場合のセグメントの長さは、変数 blob_seg_len に
入っているバイト数(セグメント長)によって決められます。
6
ループを使用して、2 番め以降のセグメントを取り出します。この場合、SQLCODE を
使って取り出しのたびに状態を確認します。SQLCODE には、BLOB データの全セグメ
ントの取り出しが終わると 100 が設定されます。また、取り出されたセグメントが本来
のセグメントより短かったとき(取り出されたのが本来のセグメントの一部だった場
合)には、SQLCODE には 101 が設定されます。
while (SQLCODE != 100 || SQLCODE == 101)
{
printf("%*.*s", blob_seg_len, blob_seg_len, blob_segment_buf);
EXEC SQL
FETCH BC INTO :blob_segment_buf:blob_seg_len;
}
このように SQLCODE を記述した場合、前述のように、FETCH によって取り出された
セグメントが本来のセグメント長に達していないと、SQLCODE にエラーコード 101 が
設定されます。
たとえば、セグメントバッファの長さが 40 で、特定のセグメントの長さが 60 の場合、
最初の FETCH は、セグメントに残っているデータを示すエラーコード 101 が生成され
ます。2 番めの FETCH は、残りの 20 バイトのデータを読み取り、SQLCODE に 0 が設
定され、次のセグメントの読み取りの準備ができていることを示します。また、そのセ
グメントが Blob データの最後のセグメントである場合は、100 が設定されます。
7
BLOB 読み取りカーソル(BC)を閉じます。
EXEC SQL
CLOSE BC;
8
テーブルカーソルを閉じます。
第 8 章 BLOB データの操作
8-7
SQL での BLOB データへのアクセス
EXEC SQL
CLOSE TC;
BLOB データの挿入
サンプルプログラムを例にして、TOURISM テーブルの GUIDEBOOK 列に BLOB データを
挿入する場合の手順を説明します。
1
次のようにして変数を宣言します。それぞれ、BLOB ID、BLOB データ、STATE 列の
データ、セグメント長を格納するのための変数です。
EXEC SQL
BEGIN DECLARE SECTION;
BASED ON TOURISM.GUIDEBOOK blob_id;
BASED ON TOURISM.GUIDEBOOK.SEGMENT blob_segment_buf;
BASED ON TOURISM.STATE state;
unsigned short blob_seg_len;
EXEC SQL
END DECLARE SECTION;
• 上の文で、BASED ON … SEGMENT 構文は、データが BLOB の場合に必要になりま
す。ここでは、変数 blob_segment_buf を宣言しています。FETCH の処理では、この
変数に BLOB データのセグメント(1 つ)が格納されることになります。BASED ON
ディレクティブの詳細は、『言語リファレンス』を参照してください。
2
BLOB データを挿入するためのカーソル(BLOB 挿入カーソル)を宣言します。
EXEC SQL
DECLARE BC CURSOR FOR INSERT Blob GUIDEBOOK INTO TOURISM;
3
BLOB 挿入カーソルを開きます。INTO の右には、BLOB ID を格納する変数を指定します。
EXEC SQL
OPEN BC INTO :blob_id;
4
変数 blob_segment_buf(バッファ)にセグメントを格納し、セグメント長を計算すると
ともに、INSERT CURSOR 文を使ってセグメントを書き込みます。
sprintf(blob_segment_buf, 'Exploring Napa County back roads');
blob_segment_len = strlen(blob_segment_buf);
EXEC SQL
INSERT CURSOR BC VALUES (:blob_segment_buf:blob_segment_len);
ループを使って上の処理を繰り返し、BLOB データのセグメントを全部書き込みます。
5
BLOB 挿入カーソルを閉じます。
EXEC SQL
CLOSE BC;
6
INSERT 文を使用して、TOURISM テーブルに Blob データを含む新規の行を追加します。
EXEC SQL
INSERT INTO TOURISM (STATE,GUIDEBOOK) VALUES ('CA',:blob_id);
8-8 埋 め 込 み S Q L ガ イ ド
SQL での BLOB データへのアクセス
7
変更をデータベースにコミットします。
EXEC SQL
COMMIT;
BLOB データの更新
BLOB データを直接更新することはできません。BLOB データを更新する場合、まず新規の
BLOB データを作成し(BLOB 挿入カーソルを宣言し、そのカーソルを開く)、バッファに
既存の BLOB データを読み取ります。その BLOB データに修正を加えた後、修正済みの
BLOB データを新規の BLOB データに書き込むという操作を行います。
最後に、既存の BLOB
データをこの新規の BLOB データに置き換えます。
新規の BLOB データの作成から BLOB データの置き換えまでの手順は、次のとおりです。
1
BLOB データを挿入するためのカーソル(BLOB 挿入カーソル)を宣言します。
EXEC SQL
DECLARE BC CURSOR FOR INSERT BLOB GUIDEBOOK INTO TOURISM;
2
BLOB 挿入カーソルを開きます。INTO の右には、BLOB ID を格納する変数を指定しま
す。
EXEC SQL
OPEN BC INTO :blob_id;
3
変数 blob_segment_buf(バッファ)に既存の BLOB データのセグメントを格納し、セグ
メントの長さを計算して必要な修正を行います。この後、INSERT CURSOR 文を使って
セグメントを書き込みます。
/* 古い Blob セグメントデータの最初 / 次のセグメントを
* blob_segment_buf; に自動的に読み取る */
EXEC SQL
INSERT CURSOR BC VALUES (:blob_segment_buf:blob_segment_len);
ループを使って上の処理を繰り返し、BLOB データのセグメントを全部書き込みます。
4
BLOB 挿入カーソルを閉じます。
EXEC SQL
CLOSE BC;
5
ここまでで新規の BLOB データの作成が完了したので、最後に UPDATE 文を使用して、
テーブルの新規の BLOB データと既存の BLOB データを入れ替えます。記述は次のよう
になります。
EXEC SQL UPDATE TOURISM
SET
GUIDEBOOK = :blob_id;
WHERE CURRENT OF TC;
メモ
上の TC は宣言済みのテーブルカーソルで、このカーソルにより、テーブルの更新対象の行
が特定され、その行が取り出されるとともに更新が行われます。
第 8 章 BLOB データの操作
8-9
SQL での BLOB データへのアクセス
BLOB データが TEXT の場合も同じ手順で更新できます。つまり、既存の BLOB テキスト
データを変数(バッファ)に読み取り、修正した後、そのデータを UPDATE 文を使って既
存の BLOB データに上書きします。
BLOB データの削除
BLOB データの削除には、2 とおりの方法があります。1 つは、BLOB が格納されている行自
体を削除する方法です。もう 1 つは、BLOB が格納されている列に NULL、または別の BLOB
データの BLOB ID を入れる(つまり、別の BLOB データをもとに新規の BLOB データを作
成する)方法です。
NULL を入れて BLOB データを削除する場合、次のように記述します。ここでは、TOURISM
テーブルの GUIDEBOOK 列に NULL が格納されます。
EXEC SQL UPDATE TOURISM
SET
GUIDEBOOK = NULL;
WHERE CURRENT OF TC;
なお、上記のように BLOB データを削除したときでも、BLOB データがすぐに削除されるわ
けではありません。BLOB データは、実際には InterBase によりバージョンクリーンアップ
が実行された時点で削除されます。また、次の文により実際の削除と同時に BLOB データに
占有されていたスペースが解放されます。
EXEC SQL
UPDATE TABLE SET Blob_COLUMN = NULL WHERE ROW = :myrow;
EXEC SQL
COMMIT;
/* すべてのアクティブなトランザクションの完了を待機します */
/* データベースのスイープを実行します */
ガベージコレクションを実行する際、削除対象のレコードに新しいバージョンのものがあ
れば、そのバージョンがなんらかの BLOB ID を参照しているかどうかの検査が行われます。
この検査で BLOB ID を参照していなければ、レコード(BLOB)が削除されます。
BLOB ガベージコレクション処理は、次のように実行されます。レコードに BLOB ID が格納
されている場合は、使用されている BLOB ストレージの種類が調査されます。BLOB が 1 つ
のページにある場合は、行インデックスインジケータが解放されます。1 つのページに
BLOB だけがある場合は、そのページが解放されていることがページインジケータによって
示されます。BLOB が一連のページにある場合は、BLOB インデックスが読み取られ、すべ
てのページが解放されます。Blob 自体を取得する必要はありません。
8-10 埋 め 込 み S Q L ガ イ ド
API 呼び出しによる BLOB データへのアクセス
API 呼び出しによる BLOB データへのアクセス
BLOB データに対しては、InterBase に用意されている API 呼び出しを使ってアクセスする
こともできます。この種の API 呼び出しとしては次のようなものがあり、アクセスのほか、
BLOB データの操作も行うことができます。
表 8.2
BLOB に関する API 呼び出し
関数
説明
isc_blob_default_desc2()
BLOB デスクリプタデータ構造体をデフォルト設定のままロードし
ます。
isc_blob_gen_bpb2()
ソース BLOB デスクリプタおよびターゲット BLOB デスクリプタを
もとに BLOB パラメータバッファ(BPB)を生成します。BPB の生成
により、BLOB サブタイプとキャラクタセットへの動的アクセスが可
能になります。
isc_blob_info()
開いている BLOB に関する情報を返します。
isc_blob_lookup_desc2()
BLOB のサブタイプ、キャラクタセット、セグメントサイズを検索
し、BLOB デスクリプタに格納します。
isc_blob_set_desc2()
BLOB デスクリプタの各パラメータの値を引数で指定した値に設定
します。
isc_cancel_blob()
BLOB を破棄するとともに内部領域を解放します。
isc_close_blob()
開いている BLOB を閉じます。
isc_create_blob2()
BLOB を格納するための場所を作成するとともに、BLOB を開き、書
き込みができる状態にします。また、オプションで BLOB データの
サブタイプを変換するためのフィルタを指定できます。
isc_get_segment()
開いている BLOB からセグメントを読み取ります。
isc_open_blob2()
抽出とフィルタリング(オプション)を行うために、既存の BLOB
を開きます。
isc_put_segment()
BLOB セグメントを書き込みます。
isc_blob_default_desc2()、isc_blob_gen_bpb2()、isc_blob_lookup_desc2()、および
isc_blob_set_desc2() は、長さ METADATALENGTH の長いメタデータ名をサポートします。
isc_blob_default_desc() などの以前の呼び出しは、32 バイト以下のメタデータ名しかサポート
しません。
API 呼び出しの種類と概要は以上のとおりです。詳細は、
『API ガイド』を参照してくださ
い。
BLOB データのフィルタリング
BLOB フィルタを扱う場合、BLOB のサブタイプについて理解しておくことが必要です。こ
れは、BLOB フィルタが、BLOB データのサブタイプを別のサブタイプに変換するルーチン
だからです。InterBase には事前に、サブタイプ 0 をサブタイプ 1(TEXT)に変換するため
第 8 章 BLOB データの操作
8-11
BLOB データのフィルタリング
の BLOB フィルタ、およびサブタイプ 1(TEXT)をサブタイプ 0 に変換するための BLOB
フィルタの 2 つが用意されています。この 2 つの BLOB フィルタを標準 InterBase フィルタ
または内部フィルタと呼んでいます。このほか、BLOB フィルタは、データの変換が必要な
場合にユーザーが独自に作成することが可能で、この BLOB フィルタを外部 BLOB フィル
タと言います。たとえば、ビットマップイメージの形式を変換する BLOB フィルタを作成す
ることもできます。
標準 InterBase フィルタ
標準 InterBase フィルタを使用して、サブタイプ 0 の BLOB データ、つまり InterBase のシス
テムで使用される通常の BLOB データをサブタイプ 1(TEXT)の BLOB データに変換する
ことができます。また、その逆も可能です。
テキストフィルタ(データをテキストに変換する標準 InterBase フィルタ)では、サブタイ
プ 0 の BLOB データが列から読み取られる際、InterBase の標準のセグメント格納規則に基
づいて BLOB データの変換が行われます。つまり、BLOB データのセグメントにどのような
データが格納されていても、セグメントの末尾には必ず改行文字(¥n)が置かれているも
のと見なされ、その改行文字に基づいて変換されます。
したがって、まずテキストフィルタでは、最初のセグメントに対応する文字列として、先
頭から最初の改行文字を含んだ範囲の文字列が返されます。この後、2 番めのセグメントに
対応する文字列として、2 番めのセグメントの先頭から 2 番めの改行文字を含んだ範囲の文
字列が返されます。以後、同じようにして文字列が変換されます。
ヒント
非テキストのサブタイプ(サブタイプ 0)を TEXT に変換するときは、FROM にサブタイプ
0 を TO にサブタイプ 1 を指定します。
外部 BLOB フィルタ
サブタイプ 0 とサブタイプ 1 の変換用の標準 InterBase フィルタは内蔵されていますが、こ
れに対して、外部 BLOB フィルタは独自に作成するとともにライブラリに含め、アプリケー
ションにリンクする必要があります。
また、外部 BLOB フィルタは、記述、コンパイル、リンクのほか、処理する BLOB データ
が格納されているデータベースに対して、宣言を行って初めて使用できるようになります。
データベースに対する外部 BLOB フィルタの宣言
データベースに対して外部 BLOB フィルタを宣言する場合、DECLARE FILTER 文を使用し
ます。たとえば、次の文は SAMPLE という外部 BLOB フィルタの宣言例です。
EXEC SQL
DECLARE FILTER SAMPLE
INPUT_TYPE -1 OUTPUT_TYPE -2
ENTRY_POINT 'FilterFunction'
MODULE_NAME 'filter.dll';
8-12 埋 め 込 み S Q L ガ イ ド
BLOB データのフィルタリング
ここでは、フィルタの入力(INPUT_TYPE)はサブタイプが -1、出力(OUTPUT_TYPE)は
サブタイプが -2 と定義されています。また、この例では、INPUT_TYPE にはフィルタ関数
の定義で小文字のテキストが、OUTPUT_TYPE には大文字のテキストが指定されています。
つまり、この SAMPLE は、BLOB データを小文字のテキストから大文字のテキストに変換
する機能を持った外部 BLOB フィルタということになります。
ENTRY_POINT と MODULE_NAME には、InterBase により呼び出される外部ルーチンをパ
ラメータとして指定します。この呼び出しにより、外部ルーチン(フィルタ)が動作する
ことになります。例では、MODULE_NAME パラメータは filter.dll となっており、これはフィ
ルタ SAMPLE の実行ファイルを格納したダイナミックリンクライブラリ(DLL)を示しま
す。また、ENTRY_POINT パラメータでは DLL へのエントリポイント(フィルタ関数)を
指定しています。なお、この例では、ダイナミックリンクライブラリに簡単なファイル名を
使用しています。ただし、ユーザーがファイルをロードする場合を考えて、ファイル名は完
全修飾名を使って指定した方が無難です。
フィルタによる BLOB データの読み取りと書き込み
次の図は、SAMPLE フィルタによるデフォルトの処理を示したものです。このフィルタで
は、小文字のテキストが大文字のテキストに変換されます。
図 8.2
小文字のテキストから大文字のテキストへの変換
アプリケーション
abcdef
Filter
SAMPLE
Blob
ABCDEF
また、SAMPLE フィルタは大文字のテキスト(サブタイプ -2)を読み取る際も使用できま
す。この場合、大文字のテキストが小文字のテキスト(サブタイプ -1)に変換されます。
図 8.3
大文字のテキストから小文字のテキストへの変換
Blob
ABCDEF
Filter
SAMPLE
アプリケーション
abcdef
アプリケーションでのフィルタの呼び出し
アプリケーションでフィルタを呼び出すには、BLOB カーソルの宣言で FILTER オプション
を使ってフィルタを指定します。指定には FROM と TO を使用し、それぞれ、フィルタ宣
言での入力と出力のサブタイプを記述します。これで、その BLOB カーソルによる処理が行
われる場合、InterBase により自動的にフィルタが呼び出され変換が実行されます。
たとえば、次の文は、処理が INSERT の BLOB カーソル宣言の例です。ここでは、FILTER
オプションで SAMPLE フィルタを指定しており、したがって、BCINS1 カーソルによる処
理では必ず、この SAMPLE フィルタが使用されることになります。
EXEC SQL
DECLARE BCINS1 CURSOR FOR
第 8 章 BLOB データの操作
8-13
外部 BLOB フィルタの作成
INSERT Blob Blob1 INTO TABLE1
FILTER FROM -1 TO -2;
このカーソル宣言が InterBase により処理される際は、現在のデータベースに定義されてい
るフィルタの中に、FILTER オプションの FROM と TO で指定されている各サブタイプに合
致するフィルタがあるかどうかの検査が行われます。合致するフィルタがあれば、宣言した
カーソル(BCINS1)による処理で、そのフィルタが呼び出されることになります。一方、
FROM と TO で指定されている各サブタイプに合致するフィルタがなければ、アプリケー
ションに対してエラーが返されます。
外部 BLOB フィルタの作成
外部 BLOB フィルタの作成にあたっては、変換するデータの型を十分に把握しておかなけ
ればなりません。InterBase では、BLOB データに関してはデータ型の検査は厳格には行われ
ませんが、変換元のサブタイプと変換先のサブタイプとでは変換上の互換性が必要です。こ
の互換性を確保するのはプログラマの仕事となります。
フィルタの種類
フィルタは 2 つの種類に分けられます。つまり、必要に応じてセグメントごとにデータの変
換を行うものと、多数のセグメントを一括して変換するものです。
1 つのセグメントを読み取った直後に変換を行い、変換したデータをアプリケーションに渡
す処理を行うフィルタ。
BLOB 読み取りカーソルが開くと同時に、全部のセグメントを一括して読み取り、変換を
行った後、アプリケーションに対してセグメントごとにデータを送る処理を行うフィルタ。
したがって、アプリケーションでタイミングが問題となるときは、どちらの種類のフィル
タが適しているかよく検討して決める必要があります。
読み取り専用フィルタと書き込み専用フィルタ
フィルタは、使用目的や記述方法によっては、BLOB データに関して読み取り専用または書
き込み専用のどちらかとなることがあります。読み取り専用のフィルタを書き込み処理で
使用した場合、または逆の場合は、エラーが返されます。
フィルタ関数の定義
外部 BLOB フィルタを使用する場合、そのフィルタを DECLARE FILTER で宣言しておかな
ければなりません。宣言ではエントリポイントを指定します。このエントリポイントをフィ
ルタ関数と呼びます。アプリケーションで BLOB 関連の処理を実行すると、このフィルタ関
数が呼び出されます。フィルタ関数は、InterBase とフィルタとの橋渡し役で、InterBase と
フィルタとのやりとりはすべてこのフィルタ関数を介して行われます。また、フィルタ関数
から別のフィルタ関数を呼び出し、そのフィルタを実行することもできます。
8-14 埋 め 込 み S Q L ガ イ ド
外部 BLOB フィルタの作成
図 8.4
アプリケーション、InterBase、フィルタの関係
アプリケーション
InterBase
フィルタ
フィルタ関数を定義するには、DECLARE FILTER 文の ENTRY_POINT パラメータにその名
前を記述し、MODULE_NAME パラメータにフィルタ関数が含まれているオブジェクトモ
ジュールの名前を記述します。
フィルタ関数は、次の呼び出しシーケンスにしたがって宣言を行います。
filter_function_name(short action, isc_blob_ctl control);
上の文で、filter_function_name はフィルタ関数の名前で、ここに宣言するフィルタ関数の
名前を記述します。また、action は、全部で 8 つ定義されているアクションを示すパラメー
タ(isc_blob_filter_put_segment など)です。control は isc_blob_ctl、つまり BLOB 制御構造体
のインスタンスを表すパラメータです。isc_blob_ctl の定義は InterBase のヘッダーファイル
ibase.h にあります。これらのパラメータについては、この章で後述します。
次のスケルトンフィルタコードは、jpeg_filter というフィルタ関数を宣言します。
#include <ibase.h>
#define SUCCESS 0
#define FAILURE 1
ISC_STATUS jpeg_filter(short action, isc_blob_ctl control)
{
ISC_STATUS status = SUCCESS;
switch (action)
{
case isc_blob_filter_open:
. . .
break;
case isc_blob_filter_get_segment:
. . .
break;
case isc_blob_filter_create:
. . .
break;
case isc_blob_filter_put_segment:
第 8 章 BLOB データの操作
8-15
外部 BLOB フィルタの作成
. . .
break;
case isc_blob_filter_close:
. . .
break;
case isc_blob_filter_alloc:
. . .
break;
case isc_blob_filter_free:
. . .
break;
case isc_blob_filter_seek:
. . .
break;
default:
status = isc_uns_ext /* サポートされていないアクション値 */
. . .
break;
}
return status;
}
上の例で、case 文の 8 つの記述(isc_blob_filter_open など)はアクションです。アプリケー
ションの処理に応じて、このうちのいずれかがフィルタ関数宣言のパラメータである action
を介して、InterBase からフィルタ関数 jpeg_filter() に渡されます。また、フィルタ関数宣言
のパラメータである control を介して、BLOB 制御構造体のインスタンス(isc_blob_ctl)が
jpeg_filter に渡されます。
また、省略符号(…)はコードで、ここには、InterBase により渡されたアクション(イベ
ント)を受けて実行する処理を記述します。フィルタ関数宣言に渡されるアクションは、ア
プリケーションの処理の内容によって異なります。詳細は、8-18 ページの「フィルタ関数
の動作のプログラミング」を参照してください。
BLOB 制御構造体(isc_blob_ctl)は BLOB データの変換に使用される構造体で、InterBase と
フィルタの間で働きます。BLOB 制御構造体の詳細は、8-16 ページの「BLOB 制御構造体
の定義」を参照してください。
BLOB 制御構造体の定義
BLOB 制御構造体は、InterBase とフィルタとの間で機能し、この構造体を介して BLOB デー
タが変換されます。BLOB 制御構造体の宣言は、InterBase のインクルードファイル ibase.h に
あります。
BLOB 制御構造体は、次の 2 とおりの方法で使用されます。
1
アプリケーションでなんらかの BLOB 処理が行われた場合、フィルタ関数が呼び出さ
れ、同時に BLOB 制御構造体のインスタンスがそのフィルタ関数に渡されます。
2
内部フィルタ関数により、BLOB 制御構造体のインスタンスが InterBase の内部アクセ
スルーチンに渡されます。
8-16 埋 め 込 み S Q L ガ イ ド
外部 BLOB フィルタの作成
BLOB 制御構造体には各種の isc_blob_ctl フィールドが用意されており、上記のどの場合で
も、アクションに応じてなんらかの isc_blob_ctl フィールドが使用されることになります。
たとえば、アプリケーションで BLOB INSERT(BLOB データの挿入)が試みられたときは、
InterBase により isc_blob_filter_put_segment アクションと BLOB 制御構造体がフィルタ関数に
渡されます。フィルタ関数は、BLOB 制御構造体のインスタンスを InterBase に渡します。こ
の場合、InterBase に渡される BLOB 制御構造体の ctl_buffer フィールドには、書き込みに使
用するセグメントデータ、つまり、アプリケーションの BLOB INSERT 文で指定された書き
込みデータが格納されています。この場合、ctl_buffer フィールドには、フィルタ関数に渡さ
れるべきデータが格納されているので、このフィールドを IN フィールドと呼びます。また、
フィルタ関数では、isc_blob_filter_put_segment アクションが指定されている case 文で、デー
タベースに書き込みを行う処理を記述しておかなければなりません。
一方、アプリケーションで FETCH(BLOB データの取り出し)が試みられたときは、フィ
ルタ関数の中の isc_blob_filter_get_segment アクションの case 文が処理を担当することになり
ます。したがって、この場合、isc_blob_filter_get_segment アクションの case 文で、データベー
スからセグメントデータを取り出して ctl_buffer フィールドに格納する処理を記述しなけれ
ばなりません。また、ctl_buffer フィールドは、この場合はフィルタ関数からの出力に使用さ
れるため、このフィールドを out フィールドと呼んでいます。
次の表は、BLOB 制御構造体(isc_blob_ctl)の各種フィールドと内容をまとめたものです。
また、フィールドがフィルタ関数への入力に使用されるか(IN フィールド)、またはフィ
ルタ関数からの出力に使用されるか(OUT フィールド)の別も示してあります。
表 8.3
isc_blob_ctl のフィールドの説明
フィールド名
説明
(*ctl_source)()
InterBase の内部 BLOB アクセスルーチンへのポインタ。(IN)
*ctl_source_handle
InterBase の内部 BLOB アクセスルーチンに渡す、isc_blob_ctl インスタンスへ
のポインタ。(IN)
ctl_to_sub_type
変換先のサブタイプ。情報フィールド。複数の種類の変換を行う多目的フィ
ルタをサポートする。このフィールドと次の ctl_from_sub_type で、実行する
変換を特定する。((IN)
ctl_from_sub_type
変換元のサブタイプ 情報フィールド。複数の種類の変換を行う多目的フィ
ルタをサポートする。このフィールドと上の ctl_from_sub_type で、実行する
変換を特定する。((IN)
ctl_buffer_length
アクションが isc_blob_filter_put_segment の場合、ctl_buffer に格納されたセグメ
ントデータの長さを格納。
(IN)
アクションが isc_blob_filter_get_segment の場合、ctl_buffer(内容は取り出された
BLOB データ)によって示されるバッファのサイズを格納。
(IN)
ctl_segment_length
現在のセグメントの長さ。アクションが isc_blob_filter_put_segment の場合、こ
のフィールドは使用されません。
アクションが isc_blob_filter_get_segment の場合、 OUT フィールドで、取り出
されたセグメントの長さを格納(取り出されたセグメントが一部のときは、
ctl_buffer_length で示されるバッファの長さは実際のセグメントの長さより短
くなる)
。
ctl_bpb_length
BLOB パラメータバッファの長さ。将来の改良のために予約。
第 8 章 BLOB データの操作
8-17
外部 BLOB フィルタの作成
表 8.3
isc_blob_ctl のフィールドの説明 ( 続き )
フィールド名
説明
*ctl_bpb
Blob パラメータバッファへのポインタ。将来の改良のために予約。
*ctl_buffer
セグメントバッファへのポインタ。アクションが isc_blob_filter_put_segment の
場合、IN フィールドで、セグメントデータを格納。
アクションが isc_blob_filter_get_segment の場合、 OUT フィールドで、フィル
タ関数によりアプリケーションへ返されるセグメントデータを格納。
ctl_max_segment
BLOB の最長のセグメントの長さ。初期値は 0。フィルタ関数で値を設定。情
報フィールド。
ctl_number_segments
BLOB セグメントの総数。初期値は 0。フィルタ関数で値を設定。情報フィー
ルド。
ctl_total_length
フィルタ関数で値を設定。情報フィールド。
BLOB の全体の長さ。初期値は 0。
*ctl_status
InterBase ステータスベクターへのポインタ。(OUT)
ctl_data[8]
8 つの要素からなるユーザー定義が可能な配列。このフィールドは、
isc_blob_filter_open ハンドラで作成されたメモリポインタやファイルハン
ドルなどのリソースポインタを格納します。次にフィルタ関数を呼び出し
たときは、そのリソースポインタが利用できるようになる。(IN/OUT)
BLOB 制御構造体の情報フィールドの設定
BLOB 制御構造体(isc_blob_ctl)で、ctl_max_segment、ctl_number_segments、ctl_total_length の
3 つは情報フィールドです。この 3 つのフィールドには、現在アクセスしている BLOB の情
報が格納されます。
フィルタ関数では、この 3 つの情報フィールドの値をできるだけ正しく維持するようにし
ます。ただし、フィルタの機能によっては、情報フィールドの値は必ずしも正しく維持でき
な い こ と も あ り ま す。 た とえば、セグメント単位でデータを圧縮するフィルタで
は、ctl_max_segment の値は、全セグメントの処理が終了するまで判定できません。
なお、この 3 つの情報フィールドの値は参照用です。これらが InterBase の内部処理で使用
されることはありません。
フィルタ関数の動作のプログラミング
アプリケーションで、挿入や取り出しなど BLOB へのアクセス処理が行われた場合、その
処理に応じて、InterBase からフィルタ関数に対してアクションメッセージが渡されます。
このアクションメッセージは、フィルタ関数の宣言のパラメータである action を介してフィ
ルタ関数に渡されます。アクションは全部で 8 種類あり、どのアクションがフィルタ関数に
送られるかは、アプリケーションでの BLOB へのアクセス処理の種類によって決まります。
ibase.h ファイルには、次の 8 種類のアクションが定義されています。
#define
#define
#define
#define
#define
#define
isc_blob_filter_open
isc_blob_filter_get_segment
isc_blob_filter_close
isc_blob_filter_create
isc_blob_filter_put_segment
isc_blob_filter_alloc
8-18 埋 め 込 み S Q L ガ イ ド
0
1
2
3
4
5
外部 BLOB フィルタの作成
#define isc_blob_filter_free
#define isc_blob_filter_seek
6
7
次の表は、8 種類のアクションと、これらのアクションに対応する BLOB アクセス処理をま
とめたものです。また、各アクションによる処理も掲載してあります。
表 8.4
BLOB アクセス処理
動作
契機
BLOB アクセス処理
isc_blob_filter_open
アプリケーションによって
BLOB READ カーソルが開かれ
た場合
BLOB 制御構造体の情報フィールドの値が設定され
ます。
メモリ割り当て、一時ファイルを開くなどの初期化
処理が実行されます。
必要な場合、ステータス変数が設定されます。このス
テータス変数の値は、フィルタ関数の戻り値となり
ます。
isc_blob_filter_get_segment
アプリケーションによって
BLOB FETCH 文が実行された
場合
BLOB 制御構造体の ctl_buffer と ctl_segment_length の各
フィールドの値が設定されます。ctl_buffer(が指すバッ
ファ)には変換されるセグメントが格納されます。
フィルタが BLOB をセグメント単位で変換する場
合、データの変換が実行されます。
ステータス変数が設定されます。このステータス変
数の値は、フィルタ関数の戻り値となります。
isc_blob_filter_close
アプリケーションによって
BLOB カーソルが閉じられた場
合
割り当てられているメモリの解放、一時ファイルを
閉じる、または削除するなどの終了処理が実行され
ます。
isc_blob_filter_create
アプリケーションによって
BLOB INSERT カーソルが開か
れた場合
BLOB 制御構造体の情報フィールドの値が設定され
ます。
メモリ割り当て、一時ファイルを開くなどの初期化
処理が実行されます。
必要な場合、ステータス変数が設定されます。このス
テータス変数の値は、フィルタ関数の戻り値となり
ます。
isc_blob_filter_put_segment
アプリケーションによって
BLOB INSERT 文が実行された
場合
BLOB 制御構造体を介して渡されたセグメントデー
タが変換されます。
データベースにデータの書き込みが実行されます。
なお、変換処理でセグメントの長さが変わるときは、
その対応処理が必要です。
ステータス変数が設定されます。このステータス変
数の値は、フィルタ関数の戻り値となります。
第 8 章 BLOB データの操作
8-19
外部 BLOB フィルタの作成
表 8.4
BLOB アクセス処理 ( 続き )
動作
契機
BLOB アクセス処理
isc_blob_filter_alloc
InterBase によりフィルタリング
の初期化が行われた場合。この
アクションは、アプリケーショ
ンの処理とは無関係です。
BLOB 制御構造体の情報フィールドの値が設定され
ます。
メモリ割り当て、一時ファイルを開くなどの初期化
処理が実行されます。
必要な場合、ステータス変数が設定されます。このス
テータス変数の値は、フィルタ関数の戻り値となり
ます。
isc_blob_filter_free
InterBase によるフィルタリング
が終了した場合。このアクショ
ンは、アプリケーションの処理
とは無関係です。
isc_blob_filter_seek
内部でのフィルタ使用のため予
約。この動作は、外部 BLOB フィ
ルタには使用されません。
ヒント
割り当てられているメモリの解放、一時ファイルを
閉じる、または削除するなどの終了処理が実行され
ます。
isc_blob_filter_open によりメモリポインタやファイルハンドルが作成されますが、このよう
なリソースポインタは BLOB 制御構造体(isc_blob_ctl)の ctl_data フィールドに格納してお
きます。これで、次回フィルタ関数が呼び出されたときは、このようなリソースポインタが
そのまま利用できます。
フィルタ関数の戻り値
フィルタ関数は、そのフィルタ関数による処理のステータスを整数で返すように記述しな
ければなりません。この場合の戻り値としては、InterBase の内部ルーチンにより返される
InterBase の戻り値であればどのようなものでも返すことができます。
なお、フィルタの種類によっては、フィルタ関数で直接戻り値を返すように記述しなけれ
ばならないこともあります。次の表は、BLOB の処理に関する戻り値をまとめたものです。
表 8.5
BLOB フィルタの戻り値
マクロ定数
値
意味
SUCCESS
0
フィルタによる処理が無事終了したことを示します。また、BLOB
読み取り
(isc_blob_filter_get_segment)処理では、1 つのセグメント全
体の読み取りが完了したことを表します。
FAILURE
1
処理が失敗したことを示します。一般に、処理が失敗した場合、エ
ラーの内容を示す具体的な状態戻り値が返されます。
8-20 埋 め 込 み S Q L ガ イ ド
外部 BLOB フィルタの作成
表 8.5
BLOB フィルタの戻り値
マクロ定数
値
意味
isc_uns_ext
ibase.h を参照
受け取ったアクションがフィルタで対応してないものであったこ
フィルタが読み取り専用でアクションが
とを示します。たとえば、
isc_blob_filter_put_segment(セグメント挿入)だった場合、このケー
スに該当します。
isc_segment
ibase.h を参照
BLOB 読み取り処理で返され、用意されたバッファが小さく現在の
セグメントを全部格納できなかったことを示します。この場合、格
納されたセグメントの長さ(バイト)は ctl_buffer_length で示されま
す。セグメントの残りの部分は、isc_blob_filter_get_segment により読
み取ることができます。
isc_segstr_eof
ibase.h を参照
BLOB 読み取り処理で返され、BLOB の末尾に達したことを示しま
す。つまり、読むべきセグメントがもう存在しないことを表します。
InterBase の戻り値の詳細は、
『言語リファレンス』を参照してください。
第 8 章 BLOB データの操作
8-21
8-22 埋 め 込 み S Q L ガ イ ド
第
第9章
章
配列の使い方
InterBase は、ほとんどのデータ型の配列をサポートしています。配列を使用すると、1 つの
列に複数のデータを集合として格納できます。格納された配列は、1 つのまとまりとして、
またはスライスと呼ばれる一連のデータ単位として扱うことができます。配列は、次のよう
な場合に使用されます。
• 個々のデータがすべて同じデータ型である場合
• 複数のデータをグループ化でき、各グループを 1 つの列に格納して管理および操作する場
合。つまり、グループを構成するデータを個別の列に置くと適切でない場合
• 複数のデータをグループ化すると同時に、グループを構成するデータに対しても個別にア
クセスする場合
配列を構成するデータを配列要素と言います。配列には、BLOB を除き、InterBase でサポー
トされているデータ型の要素を格納できます。しかし、配列型は配列要素として格納するこ
とができません。ただし、InterBase では、多次元配列がサポートされています。配列要素
は、すべて同じデータ型でなければなりません。
配列の作成
配列は、CREATE DOMAIN または CREATE TABLE の各文を使って配列の列を指定して作
成します。指定の方法は配列以外の列の場合と同じですが、配列では次元も指定しなければ
なりません。
配列インデックスの範囲は、–231 から +231–1 までです。
配列の列を指定する場合、次の文のようになります。ここでは、データ型が文字型、要素
が 4 つ、1 次元の配列の列を作成しています。
EXEC SQL
CREATE TABLE TABLE1
(
第 9 章 配列の使い方
9-1
配列の作成
NAME CHAR(10),
CHAR_ARR CHAR(10)[4]
);
上記のように、要素および次元は、データ型の右にブラケット([ ])で囲んで指定します。
CREATE TABLE と配列の指定の構文の詳細は、
『言語リファレンス』を参照してください。
多次元配列
InterBase では、16 次元までの多次元配列を扱うことができます。たとえば、2 次元、3 次元、
6 次元の 3 つの配列の列を定義する場合、記述は次のようになります。いずれも、データ型
は整数です。
EXEC SQL
CREATE TABLE TABLE1
(
INT_ARR2 INTEGER[4,5]
INT_ARR3 INTEGER[4,5,6]
INT_ARR6 INTEGER[4,5,6,7,8,9]
);
上の例では、INT_ARR2 は 4 行 5 列の配列、つまり全部で 20 の整数の要素を持つ配列にな
ります。また、INT_ARR3 は全部で 120 の整数の要素、INT_ARR6 は全部で 60480 の整数の
要素を持った配列ということになります。
重要
InterBase は、行の大きな順に多次元配列を格納します。FORTRAN のような一部のホスト言
語は、配列は列の大きな順であると解釈しています。このような場合は、InterBase とホス
ト言語の間で要素の順序を正しく変換することに注意してください。
添字範囲の指定
InterBase では、配列次元は、添字という特定の上下境界の範囲を持っています。たいてい
の場合、添字の範囲は暗黙的です。配列の最初の要素は要素 1、2 番めは要素 2、最後は要
素 n です。たとえば、次の文は、4 つの整数の配列である列を持つテーブルを作成します。
EXEC SQL
CREATE TABLE TABLE1
(
INT_ARR INTEGER[4]
);
この配列の添字は 1, 2, 3, 4 です。
各配列の次元の上下限の別のセットは、配列の列を作成するときに明示的に定義されます。
たとえば、添字の下限が 0 で始まる配列に詳しい C プログラマは、おそらく同じように添
字の下限が 0 で始まる配列の列を作成するでしょう。
配列の添字を指定するには、最初の要素の添字(lower)と最後の要素の添字(upper)を
次の構文を使って記述します。
lower:upper
9-2 埋 め 込 み S Q L ガ イ ド
配列へのアクセス
たとえば、次の文では、4 つの要素で構成され、最初の要素の添字が 0、最後の要素の添字
が 3 という 1 次元の配列の列が作成されます。
EXEC SQL
CREATE TABLE TABLE1
(
INT_ARR INTEGER[0:3]
);
この配列の添字は 0, 1, 2, 3 です。
また、多次元の配列に明示的に添字を指定する場合は、それぞれの次元ごとに両端の添字
を記述した後、カンマで区切って次の次元の添字を記述します。たとえば、2 次元で要素が
どちらも 4 つ、各次元の配列要素に 0 から 3 までの添字が割り当てられた配列の列を作成
する場合は、次のように記述します。
EXEC SQL
CREATE TABLE TABLE1
(
INT_ARR INTEGER[0:3, 0:3]
);
配列へのアクセス
InterBase では、格納されている配列を 1 つの要素として扱うことができます。このほか、
配列の中の 1 つ、または複数の要素を個別に扱うこともできます。これらの要素を配列ス
ライスと呼んでいます。配列スライスには、1 つの要素で構成されるものと隣接する複数の
要素で構成されるものの 2 種類があります。
配列に対しては、次のような処理が可能です。
• 配列からのデータの取り出し
• 配列へのデータの挿入
• 配列スライスのデータの更新
• 配列スライスからのデータの取り出し
• 検索条件での配列要素の評価
ユーザー定義関数(UDF)では、配列の要素 1 つずつしか参照できません。
また、配列に対して次の処理を実行することはできません。
• DSQL での配列の次元に対する動的参照
• 配列スライスへのデータの挿入
• 各配列要素に NULL を設定
• 配列の列に対する MIN()、MAX()、SUM()、AVG()、COUNT() の各集計関数の使用
• SELECT の GROUP BY 句での配列の列の指定
• 配列スライスを作成元とするビューの作成
第 9 章 配列の使い方
9-3
配列へのアクセス
配列からのデータの取り出し
配列からは、次の手順でデータを取り出すことができます。
1
配列変数を宣言します。この場合、配列変数は、配列のデータを格納するのに十分な大
きさが必要です。たとえば、次の文は、配列変数を 3 つ作成する例です。
EXEC SQL
BEGIN DECLARE SECTION;
BASED ON TABLE1.CHAR_ARR char_arr;
BASED ON TABLE1.INT_ARR int_arr;
BASED ON TABLE1.FLOAT_ARR float_arr;
EXEC SQL
END DECLARE SECTION;
2
カーソルを宣言し、データを選択する配列の列を指定します。たとえば、次のように記
述します。
EXEC SQL
DECLARE TC1 CURSOR FOR
SELECT NAME, CHAR_ARR[], INT_ARR[]
FROM TABLE1;
指定する配列名の右には必ずブラケット([ ])を付けなければなりません。このブラ
ケットがないと、配列のデータではなく、その列の配列 ID が読み取られます。
ブラケットを付けない場合に読み取られる配列 ID は、実際には BLOB ID です。ただ
し、この配列 ID は、InterBase の API 呼び出しを使って配列のデータにアクセスすると
きに利用できます。
3
カーソルを開いて、データを取り出します。
EXEC SQL
OPEN TC1;
EXEC SQL
FETCH TC1 INTO :name, :char_arr, :int_arr;
メモ
上の例ではカーソルを使って配列のデータを取り出していますが、必ずしもカーソルを使
用する必要はありません。たとえば、単一行 SELECT でデータを取り出してもかまいませ
ん。
上のように、配列のデータは行を基準に取り出されるので、取り出しの際は、この点に注
意しなければなりません。たとえば、2 行 3 列構成の 2 次元の配列では、行 1 の 3 つの要素
がまず取り出されます。この後、行 2 の 3 つの要素が取り出されることになります。
配列へのデータの挿入
配列にデータを挿入するには INSERT を使用します。この場合、挿入するデータは配列要素
すべてを埋めるものでなければなりません。それ以外の場合にはエラーが発生します。
配列へのデータの挿入は、次の手順で行います。
9-4 埋 め 込 み S Q L ガ イ ド
配列へのアクセス
1
配列のデータを格納する変数を宣言します。この場合、BASED ON 句を使用すると便利
で、ちょうど配列全体を埋める大きさの配列変数を用意できます。たとえば、次の文
は、BASED ON を使ってこのような配列変数を 3 つ作成する例です。
EXEC SQL
BEGIN DECLARE SECTION;
BASED ON TABLE1.CHAR_ARR char_arr;
BASED ON TABLE1.INT_ARR int_arr;
BASED ON TABLE1.FLOAT_ARR float_arr;
EXEC SQL
END DECLARE SECTION;
2
3
変数にデータを入れます。
INSERT を使って配列に書き込みを行います。次に例を示します。
EXEC SQL
INSERT INTO TABLE1 (NAME, CHAR_ARR, INT_ARR, FLOAT_ARR)
VALUES ('Sample', :char_arr, :int_arr, :float_arr);
4
変更内容をコミットします。
EXEC SQL
COMMIT;
重要
配列へデータを挿入する場合、配列要素全部がデータで埋まるようにする必要があります。
そうでない場合、結果は保証されません。
配列スライスのデータの取り出し
SELECT 文を使用して、配列中の隣接する複数の要素を取り出すことができます。この配列
中の隣接する複数の要素を配列スライスと言います。この場合、SELECT で、配列名の右に
ブラケット([ ])を使って配列スライスを指定します。ブラケットの中には、取り出す要素
を数値(添字)を使って指定します。配列が 1 次元で取り出すデータが 1 つのときは、添字
は 1 つになります。たとえば、1 次元配列の中の 2 番めの要素を取り出す場合、次の文のよ
うになります。
EXEC SQL
SELECT JOB_TITLE[2]
INTO :title
FROM EMPLOYEE
WHERE LAST_NAME = :lname;
また、1 次元配列の中の隣接する複数の要素を取り出すときは、その範囲の最初の要素
(lower_bound)と最後の要素(upper_bound)を添字で指定します。数値の間にはコロン
を挿入します。次のような構文になります。
[lower_bound:upper_bound]
次は、1 次元配列の中の隣接する 3 つの要素を取り出す場合の記述です。
EXEC SQL
SELECT JOB_TITLE[2:4]
INTO :title
第 9 章 配列の使い方
9-5
配列へのアクセス
FROM EMPLOYEE
WHERE LAST_NAME = :lname;
多次元配列では、それぞれの次元について取り出すデータの範囲を指定しなければなりま
せん。この場合、範囲は次元ごとにカンマで区切ります。構文は次のとおりです。
[lower:upper, lower:upper [, lower:upper ...]]
メモ
この構文で、外側の太字のブラケットは必ず入力しなければなりません。
次の文は、2 次元配列中、2 行(行 1、2)の 3 要素(列 1、2、3)を取り出す例です。
EXEC SQL
DECLARE TC2 CURSOR FOR
SELECT INT_ARR[1:2,1:3]
FROM TABLE1
InterBase では配列のデータは行を基準として扱われるため、ブラケットの最初の範囲が行
を表します。また、次の範囲が列を表し、各行について、ここで指定された列のデータが取
り出されるというように処理が行われます。
次に、配列スライスのデータを選択する場合の手順を説明します。
1
取り出すデータを格納するのに十分な大きさの変数を宣言します。次に例を示します。
EXEC SQL
BEGIN DECLARE SECTION;
char char_slice[11]; /* CHAR(10) データ型の 11 バイトの文字列 */
long int_slice[2][3];
EXEC SQL
END DECLARE SECTION;
上で、最初の char_slice 変数は、CHAR_ARR 列の 1 つの要素を格納するための変数で
す。また、2 番めの int_slice 変数は、INT_ARR 整数列の配列スライス(6 要素)を格納
するためのものです。
2
カーソルを宣言するとともに、データを読み取る配列スライスを指定します。次はその
例です。
EXEC SQL
DECLARE TC2 CURSOR FOR
SELECT CHAR_ARR[1], INT_ARR[1:2,1:3]
FROM TABLE1
3
カーソルを開いて、データを取り出します。
EXEC SQL
OPEN TC2;
EXEC SQL
FETCH TC2 INTO :char_slice, :int_slice;
配列スライスのデータの更新
配列スライスのデータは、カーソルを使って更新できます。配列スライスのデータの更新
は、次の手順で行います。
9-6 埋 め 込 み S Q L ガ イ ド
配列へのアクセス
1
取り出すデータを格納するのに十分な大きさの変数を宣言します。たとえば、次のよう
になります。
EXEC SQL
BEGIN DECLARE SECTION;
char char_slice[11]; /* CHAR(10) データ型の 11 バイトの文字列 */
long int_slice[2][3];
EXEC SQL
END DECLARE SECTION;
上の例では、最初の char_slice 変数は、CHAR_ARR 配列(定義については配列の作成
のセクションを参照)の 1 つの要素を格納するための変数です。また、2 番めの int_slice
変数は、INT_ARR 整数列の配列スライス(6 要素)を格納するためのものです。
2
SELECT を使用して、更新する配列スライスのデータを取り出します。たとえば、
CHAR_ARR 列(この列では取り出す要素は 1 つ)と INT_ARR 列から配列スライスの
データを取り出す場合、記述は次のようになります。
EXEC SQL
DECLARE TC1 CURSOR FOR
SELECT CHAR_ARRAY[1], INT_ARRAY[1:2,1:3] FROM TABLE1;
EXEC SQL
OPEN TC1;
EXEC SQL
FETCH TC1 INTO :char_slice, :int_slice;
上の例では、CHAR_ARR 列と INT_ARR 列に格納されている配列スライスのデータが
それぞれ、char_slice と int_slice の 2 つの変数に格納されます。
3
4
2 つの変数に新規または修正済みのデータをロードします。
UPDATE 文を使用して、データを配列スライスに挿入します。char_slice と int_slice の 2
つの変数に格納されているデータを CHAR_ARR 列と INT_ARR 列に挿入する場合、
UPDATE 文の記述は次のようになります。
EXEC SQL
UPDATE TABLE1
SET
CHAR_ARR[1] = :char_slice,
INT_ARR[1:2,1:3] = :int_slice
WHERE CURRENT OF TC1;
5
変更内容をコミットします。
EXEC SQL
COMMIT;
次の図は、この例によるデータ更新後の CHAR_ARR 列と INT_ARR 列の内容を示したもの
です。なお、添字は 0 で始まっています。また、値は参考値です。
第 9 章 配列の使い方
9-7
配列へのアクセス
char_arr values:
[0]:string0 [1]:NewString [2]:string2 [3]:string3
int_arr values:
[0][0]:0 [0][1]:1
[1][0]:10 [1][1]:999
[2][0]:20 [2][1]:999
[3][0]:30 [3][1]:31
[0][2]:2
[1][2]:999
[2][2]:999
[3][2]:32
[0][3]:3
[1][3]:999
[2][3]:999
[3][3]:33
更新された値
検索条件での配列要素の評価
WHERE 句の検索条件を使用して、配列の中の要素を評価することができます。検索できる
のは 1 つの配列要素に限られます。次に例を示します。
EXEC SQL
DECLARE TC2 CURSOR FOR
SELECT CHAR_ARR[1], INT_ARR[1:2,1:3]
FROM TABLE1
WHERE SMALLINT_ARR[1,1,1] = 111;
重要
検索条件で検索できるのは配列の中の 1 つの要素だけで、配列スライス(複数の要素の集
合)を検索することはできません。
変数による配列の添字の指定
配列の添字は、整数の変数を使って表すことができます。たとえば、次は、配列の添字とし
て getval と testval という 2 つの変数を使用しているカーソル宣言の例です。
EXEC SQL
DECLARE TC2 CURSOR FOR
SELECT CHAR_ARR[1], INT_ARR[:getval:1,1:3]
FROM TABLE1
WHERE FLOAT_ARR[:testval,1,1] = 111.0;
配列と算術式
WHERE 句の検索条件では、配列に算術式を組み込むことができます。たとえば、次は、配
列の記述に算術式を使った WHERE 句の例で、配列のデータのうち、この検索条件に適合
する行が 1 行ずつ取り出されます。
for (i = 1; i < 100 && SQLCODE == 0; i++)
{
EXEC SQL
SELECT ARR[:i] INTO :array_var
FROM TABLE1
WHERE ARR1[:j + 1] = 5;
process_array(array_var);
}
9-8 埋 め 込 み S Q L ガ イ ド
第
章
ストアドプロシージャ
第 10 章
ストアドプロシージャは、SQL 文を組み合わせて作成した独立型のプログラムコードで、
データベース中にメタデータとして格納されます。
アプリケーションで実行できるストアドプロシージャとの対話は以下のとおりです。
• ストアドプロシージャに対してパラメータを渡し、戻り値を受け取ることができます。
• ストアドプロシージャを直接呼び出してなんらかの処理を行うことができます。
• SELECT 文でテーブルやビューのかわりにストアドプロシージャを指定できます。
ストアドプロシージャには、次のような利点があります。
• 異なるアプリケーションでコードを共有できます。つまり、よく使用する処理をストアド
プロシージャとして作成してデータベースに格納しておくと、そのデータベースに対して
アクセスを行うアプリケーションであれば、どのアプリケーションからでもストアドプロ
シージャの利用が可能になります。ストアドプロシージャは、InterBase の対話型 SQL ツー
ルである isql でも使用できます。
• 効率のよいモジュール設計が可能です。ストアドプロシージャは複数のアプリケーション
で使用できるため、コードをアプリケーションごとに記述する必要がなくなります。また、
アプリケーションのサイズも縮小できます。
• 保守の簡略化が図れます。ストアドプロシージャの内容を変更した場合、変更は、そのス
トアドプロシージャを使用しているアプリケーションすべてに対して自動的に有効になり
ます。このため、アプリケーションの再コンパイル、再リンクが不要となります。
• 動作性能、特にリモートクライアントによるアクセスの動作パフォーマンスが向上します。
これは、ストアドプロシージャがクライアントではなくサーバーによって実行されるため
です。
この章では、アプリケーションでのストアドプロシージャの呼び出しと実行について説明
します。ストアドプロシージャの作成方法の詳細は、
『データ定義ガイド』を参照してくだ
さい。
第 10 章 ストアドプロシージャ
10-1
ストアドプロシージャの使い方
ストアドプロシージャの使い方
ストアドプロシージャの呼び出し方には 2 種類あり、その呼び出し方に応じて、便宜上ス
トアドプロシージャを次の 2 種類に分けています。
• アプリケーションの SELECT 文で、テーブルやビューのかわりに指定したストアドプロ
シージャを選択プロシージャ(select procedure)と言います。選択プロシージャでは、必ず
1 つ、または複数の値が返されるように出力パラメータを指定しなければなりません。この
指定がない場合、エラーとなります。
• アプリケーションで EXECUTE PROCEDURE 文を使ってストアドプロシージャを直接呼び
出す場合、そのストアドプロシージャを実行可能プロシージャ(excutable procedure)と呼
びます。実行可能プロシージャでは、必ずしも値が返される必要はありません。
上記の 2 種類のストアドプロシージャはいずれも CREATE PROCEDURE を使って定義し、
どちらの場合も構文は同じです。ただし、コードでの記述方法と用途は異なります。つま
り、選択プロシージャでは必ず 1 行、または複数行(該当行が見つからないときにはなし)
が取り出されます。したがって、プログラムから見ると、選択プロシージャはテーブルま
たはビューと同等ということになります。一方、実行可能プロシージャはルーチンそのもの
で、プログラムから呼び出され、通常なんらかの値を返します。
ストアドプロシージャは、内容によって、同一のものを選択プロシージャと実行可能プロ
シージャの両方に使用することもできますが、あまりお勧めできません。ストアドプロシー
ジャは、通常 SELECT 文で使用するプロシージャ(選択プロシージャ)と、EXECUTE
PROCEDURE 文で使用するプロシージャ(実行可能プロシージャ)に分けて記述するのが
原則です。ストアドプロシージャの作成方法の詳細は、
『データ定義ガイド』を参照してく
ださい。
ストアドプロシージャとトランザクション
ストアドプロシージャは、その記述部分で起動しているトランザクションとともに動作し
ます。したがって、ともに機能しているトランザクションの動作が ROLLBACK によって
ロールバックされた場合、そのストアドプロシージャの動作もロールバックされます。ま
た、ストアドプロシージャの動作は、ともに機能しているトランザクションの処理がコミッ
トされて初めて有効になります。
ストアドプロシージャとセキュリティ
アプリケーションでストアドプロシージャを呼び出す場合、アプリケーションのユーザー
に対してストアドプロシージャの EXECUTE 特権が与えられていなければなりません。
EXECUTE 特権の付与には GRANT 文を使用します。また、付与した EXECUTE 特権を取り
消す場合は REVOKE 文を使用します。特権の付与の詳細は、
『データ定義ガイド』を参照し
てください。
10-2 埋 め 込 み S Q L ガ イ ド
選択プロシージャの使い方
また、ストアドプロシージャでデータベースのオブジェクトにアクセスする場合、必ずし
たがわなければならないことがあります。アプリケーションのユーザーまたは呼び出した
ストアドプロシージャのどちらかに、アクセスするオブジェクトに対する特権が付与され
ていなければなりません。ストアドプロシージャに特権を付与するには GRANT 文を使用
します。また、特権の取り消しには REVOKE 文を使用します。
選択プロシージャの使い方
選択プロシージャは、SELECT 文でテーブルやビューのかわりに指定して使用します。これ
で、選択プロシージャ内の定義にしたがって該当行が取り出されます(該当行がない場合、
行は取り出されません)。また、選択プロシージャでは、必ず出力パラメータを指定しなけ
ればなりません。この出力パラメータがない場合はエラーとなります。戻り値が特定されな
いときは、デフォルトで NULL が返されます。
テーブルやビューに比べて、選択プロシージャには次の利点があります。
• 入力パラメータを指定できるとともに、その出力を利用できます。
• 制御文、ローカル変数、データ操作文を使用できるので、アプリケーションの柔軟性が大
幅に向上します。
CREATE PROCEDURE を使って選択プロシージャを定義する場合、まず、選択プロシージャ
の名前を記述し、次に入力パラメータをかっこで囲んで指定します。入力パラメータが複
数のときは、各引数をカンマで区切ります。
たとえば、次の文は、GET_EMP_PROJ という名前の選択プロシージャを定義している isql
スクリプトファイルの例です。この GET_EMP_PROJ は、入力パラメータとして社員番号
(EMP_NO)が渡されると、その社員が担当しているプロジェクト番号(EMP_PROJ)を返
すという選択プロシージャです。
CREATE PROCEDURE GET_EMP_PROJ (emp_no SMALLINT)
RETURNS (emp_proj SMALLINT) AS
BEGIN
FOR SELECT PROJ_ID
FROM EMPLOYEE_PROJECT
WHERE EMP_NO = :emp_no
INTO :emp_proj
DO
SUSPEND;
END ;
次の文は、この GET_EMP_PROJ の SELECT 文での使用例で、ここでは、取り出されたプロ
ジェクト番号(PROJ_ID)は変数の number に渡されます。
SELECT PROJ_ID FROM GET_EMP_PROJ (:number);
第 10 章 ストアドプロシージャ
10-3
実行可能プロシージャの使い方
選択プロシージャの呼び出し
アプリケーションで選択プロシージャを使用する場合、通常のテーブル名やビュー名のか
わりに、その選択プロシージャの名前を記述します。テーブルやビューの指定が可能であ
れば、どの箇所でも選択プロシージャを指定できます。また、選択プロシージャの右には入
力パラメータをかっこで囲んで記述します。パラメータが複数のときは、各引数をカンマ
で区切ります。
EXEC SQL
SELECT PROJ_ID FROM GET_EMP_PROJ (:emp_no)
ORDER BY PROJ_ID;
重要
InterBase では、選択プロシージャを呼び出してビューの作成を行うことはできません。
カーソル宣言での選択プロシージャの使用
選択プロシージャは、カーソル宣言の中でも使用できます。たとえば、次は、PROJECTS と
いう名前のカーソル宣言で、テーブルのかわりに GET_EMP_PROJ 選択プロシージャを指定
している例です。
EXEC SQL
DECLARE PROJECTS CURSOR FOR
SELECT PROJ_ID FROM GET_EMP_PROJ (:emp_no)
ORDER BY PROJ_ID;
また、次の例は、この PROJECTS カーソルを埋め込み SQL で記述している C のコードです。
このコードでは、プロジェクト番号が標準出力に出力されます。
EXEC SQL
OPEN PROJECTS
/* 従業員プロジェクトを出力します */
while (SQLCODE == 0)
{
EXEC SQL
FETCH PROJECTS INTO :proj_id :nullind;
if (SQLCODE == 100)
break;
if (nullind == 0)
printf("¥t%s¥n", proj_id);
}
実行可能プロシージャの使い方
実行可能プロシージャは、アプリケーションで直接呼び出して使用します。この実行可能
プロシージャは、複数のアプリケーションで同一のデータベースに対して同じ処理を行う
場合に便利です。実行可能プロシージャでは、実行時に入力パラメータを指定することがで
10-4 埋 め 込 み S Q L ガ イ ド
実行可能プロシージャの使い方
きます。この場合、このパラメータが呼び出し元のプログラムから渡されます。また、オ
プションで出力パラメータを指定することもでき、この場合、呼び出し元のプログラムに
1 つの行が返されます。
入力パラメータは、実行可能プロシージャの名前の右に記述します。入力パラメータが複
数の場合、各引数をカンマで区切ります。
メモ
実行可能プロシージャでは、複数行を返すことはできません。
実行可能プロシージャの実行
アプリケーションで実行可能プロシージャを実行する場合、次の構文で実行可能プロシー
ジャを記述します。
EXEC SQL
EXECUTE PROCEDURE name [:param [[INDICATOR]:indicator]]
[, :param [[INDICATOR]:indicator] ...]
[RETURNING_VALUES :param [[INDICATOR]:indicator]
[, :param [[INDICATOR]:indicator]...]];
実行可能プロシージャで入力パラメータを指定する場合、入力パラメータはリテラル値(7
や “Fred” など)または変数のどちらでもかまいません。一方、出力パラメータを指定する
場合、RETURNING_VALUES 句で変数を記述しなければなりません。戻り値は、この変数
に格納されることになります。
たとえば、DEPT_BUDGET という実行可能プロシージャをリテラルの入力パラメータを
使って実行する場合、記述は次のようになります。
EXEC SQL
EXECUTE PROCEDURE DEPT_BUDGET 100 RETURNING_VALUES :sumb;
次の文も同じプロシージャを呼び出していますが、入力パラメータにリテラル値ではなく
ホスト変数を使用しています。
EXEC SQL
EXECUTE PROCEDURE DEPT_BUDGET :rdno RETURNING_VALUES :sumb;
インジケータ変数
実行可能プロシージャの入力パラメータと出力パラメータには、どちらもインジケータ変
数を添えることができます。このインジケータ変数により、NULL の検査が可能になりま
す。特に、出力パラメータの値が NULL(不定)であるかどうかを検査する場合、必ずイン
ジケータ変数を使用します。インジケータ変数は INDICATOR の右に記述しますが、この
INDICATOR は省略することもできます。インジケータ変数がマイナスのときは、パラメー
タの値が NULL(不定)であることを示します。また、0 のときはパラメータの値が NULL
以外であることを表します。インジケータ変数の詳細は、第 6 章「データ処理」を参照し
てください。
DSQL アプリケーションでのストアドプロシージャの実行
ストアドプロシージャは DSQL アプリケーションで実行することもできます。実行は、次
の手順で行います。
第 10 章 ストアドプロシージャ
10-5
実行可能プロシージャの使い方
1
PREPARE 文を使ってストアドプロシージャの分析と実行の準備を行います。PREPARE
の構文は次のとおりです。
EXEC SQL
PREPARE sql_statement_name FROM :var | '<statement>';
2
DESCRIBE INPUT を使用して、入力用の XSQLDA を用意します。構文は次のとおりで
す。
EXEC SQL
DESCRIBE INPUT sql_statement_name INTO SQL DESCRIPTOR input_xsqlda;
3
DESCRIBE OUTPUT を使用して、出力用の XSQLDA を用意します。構文は次のとおり
です。
EXEC SQL
DESCRIBE OUTPUT sql_statement_name INTO SQL DESCRIPTOR
output_xsqlda;
なお、出力用の XSQLDA は、ストアドプロシージャによって値が返される場合に限り
必要になります。
4
次のようにして、文を実行します。
EXEC SQL
EXECUTE statement USING SQL DESCRIPTOR input_xsqlda
INTO DESCRIPTOR output_xsqlda;
ストアドプロシージャの入力パラメータを疑問符(?)にして記述しておくと、実行時の値
を渡すことができるようになります。次は、ADD_EMP_PROJ というストアドプロシージャ
のパラメータを疑問符で記述し、DSQL で用意と実行を行う例です。
. . .
strcpy(uquery, "EXECUTE PROCEDURE ADD_EMP_PROJ ?, ?");
. . .
EXEC SQL
PREPARE QUERY FROM :uquery;
EXEC SQL
DESCRIBE INPUT QUERY INTO SQL DESCRIPTOR input_xsqlda;
EXEC SQL
DESCRIBE OUTPUT QUERY INTO SQL DESCRIPTOR output_xsqlda;
EXEC SQL
EXECUTE QUERY USING SQL DESCRIPTOR input_xsqlda INTO SQL DESCRIPTOR
output_xsqlda;
. . .
10-6 埋 め 込 み S Q L ガ イ ド
第
章
イベントの操作
第 11 章
この章では、InterBase のイベントメカニズムについて説明します。また、アプリケーショ
ン上で、イベントとの関係を登録してイベントに応答する方法について説明します。
InterBase のイベントメカニズムを利用することで、いずれかのアプリケーションでなんら
かの処理やデータベースの変更が行われた場合、その処理や変更を動作中の別のアプリ
ケーションにも同時に伝えることができます。この場合、アプリケーション同士の直接の
通信は必要ありません。また、イベントが発生したかどうかを検査する定期ポーリングも
行われないので、そのための CPU 時間も節約できます。
InterBase のイベントメカニズム
InterBase では、イベントとは、トリガーやストアドプロシージャによって InterBase のイベ
ントマネージャに渡されるメッセージを言います。メッセージ(イベント)の内容は特定
の状態や動作で、INSERT、UPDATE、DELETE などによるデータベース上での変更(挿入、
更新、削除)が代表的なものとして挙げられます。イベントは、そのイベントが発生したと
きに機能していたトランザクションがコミットされた時点で、トリガーやストアドプロ
シージャによって InterBase のイベントマネージャに実際に渡されます。
トリガーやストアドプロシージャから送られてきたイベントは、InterBase のイベントマ
ネージャ側で保存、管理されます。このほか、イベントとの関係を登録しているアプリケー
ションについても、イベントマネージャ側で管理が行われます。新たなイベントがイベント
マネージャに送られるたびに、イベントマネージャから、関係するアプリケーションに対
してイベントが発生したことの通知が送られます。
このように、イベントはイベントマネージャによって管理されますが、イベントに対して
アプリケーション側で応答する場合、そのアプリケーションでは次のような準備をしてお
く必要があります。
1
2
イベントマネージャに対して、イベントとの関係を登録しておきます。
イベントマネージャからのイベントの通知を待ちます。
第 11 章 イベントの操作
11-1
イベントの発生
3
必要なイベントを識別します(アプリケーションで複数のイベントを待つ場合)。
以上、InterBase のイベントメカニズムの概要を説明しました。イベントメカニズムは次の
3 つの要素で構成されます。
• トリガーまたはストアドプロシージャ:イベントは、このトリガーやストアドプロシージャ
によってイベントマネージャに送られます。
• イベントマネージャ:このイベントマネージャによってイベントキュー(イベントの待ち
行列)が管理されます。また、イベントが発生するたびに、それがアプリケーションに通
知されます。
• アプリケーション:イベントマネージャにイベントとの関係を登録し、そのイベントが発
生するのを待っているアプリケーションです。
以上のような 3 つの要素が揃っている場合、いずれかのアプリケーションでイベントを発
生させるようなストアドプロシージャ(またはトリガー)が実行されると、そのイベント
がイベントマネージャに送られます。同時に、イベントを待つアプリケーションに対して
通知が送られ、通知を受けたアプリケーション側での実際の処理が行われます。
イベントの発生
イベントメカニズムを使用する場合、イベントを発生させるトリガーまたはストアドプロ
シージャをアプリケーションに用意しなければなりません。イベントの種類としては、
INSERT、UPDATE、DELETE などによるデータベースの変更(挿入、更新、削除)が代表
的です。このようなイベントは、それぞれ、トリガーまたはストアドプロシージャに
POST_EVENT 文を記述しておくことで発生させることができます。
POST_EVENT を記述しておいた場合、発生したイベントはトランザクションのコミットが
完了した時点でイベントマネージャに送られます。この後、イベントマネージャによっての
そのイベントに関する通知がイベントを登録しているアプリケーションに送られます。
このようなイベント発生の機能を持ったトリガーやストアドプロシージャをイベントア
ラータと呼ぶこともあります。たとえば、次はトリガー作成のための isql スクリプトで、こ
こで作成されたトリガーは、アプリケーション上でテーブルへのデータ挿入が行われるた
びにイベント(INSERT のイベント)をイベントマネージャに送る働きをします。
CREATE TRIGGER POST_NEW_ORDER FOR SALES
ACTIVE
AFTER INSERT
POSITION 0
AS
BEGIN
POST_EVENT 'new_order';
END ;
イベント名の長さには制限はありません。
メモ
POST_EVENT はストアドプロシージャまたはトリガー専用で、ストアドプロシージャとト
リガーの中だけで使用できます。
11-2 埋 め 込 み S Q L ガ イ ド
イベントとの関係の登録
トリガーとストアドプロシージャでの POST_EVENT の記述方法の詳細は、『データ定義ガ
イド』を参照してください。
イベントとの関係の登録
アプリケーション側でイベントマネージャからのイベント通知を受け取る場合、受け取り
たいイベントについて、イベントマネージャに事前に登録しておかなければなりません。こ
れで、発生したイベントの通知を待機できるようになります。イベントとの関係の登録には
EVENT INIT 文を使用します。EVENT INIT には次の 2 つの引数が必要です。
• アプリケーション独自のリクエストハンドル:このハンドルがイベントマネージャに送ら
れます。
• 通知を要求するイベント名:かっこで囲んで指定します。
最初のアプリケーション独自のリクエストハンドルは、同じものを後続の EVENT WAIT 文
でも指定します。これで、イベントマネージャからの通知を受け取る準備ができます。この
リクエストハンドルは、イベントマネージャで、特定のイベント通知をどのアプリケーショ
ンに送るかを判定するために使用されます。判定後、通知がアプリケーションに送られ、そ
の通知にアプリケーションが応答することになります。
2 番めの引数であるイベント名はかっこで括って指定します。この名前は、トリガーまたは
ストアドプロシージャからイベントマネージャに送られるイベント名と同じでなければな
りません。この名前が異なる場合、通知は行われません。
1 つのイベントとの関係を登録する場合、EVENT INIT の構文は次のようになります。
EXEC SQL
EVENT INIT request_name (event_name);
ここで、request_name はリクエストハンドルです。event_name はイベント名で、長さは 15 字
以内でなければなりません。この event_name は、引用符で囲んだ定数でも変数でもかまい
ません。
たとえば、アプリケーションで次の EVENT INIT 文を記述すると、
RESPOND_NEW というリクエストハンドルが作成され、“new_order” というイベントとの
関係が登録されます。
EXEC SQL
EVENT INIT RESPOND_NEW ('new_order');
また、次の記述では、リクエストハンドルは RESPOND_NEW で同じですが、myevent とい
う変数で示されるイベントとの関係が登録されます。
EXEC SQL
EVENT INIT RESPOND_NEW (:myevent);
以上のようにしてイベントとの関係を登録しても、このままではイベントの通知を受け取
ることはできません。このほか、EVENT WAIT を使ってイベントの通知を待つ必要があり
ます。イベントの通知の待機の詳細は、11-4 ページの「EVENT WAIT によるイベントの
通知の待機」を参照してください。
第 11 章 イベントの操作
11-3
複数のイベントとの関係の登録
メモ
イベントとの関係の登録は、EVENT INIT の他に、InterBase の API 呼び出しを使って行う
こともできます。また、イベントの通知の受け取りについては、非同期トラップ(AST)関
数を使って実現することもできます。この API 呼び出しと非同期トラップ(AST)関数の組
み合わせでは、イベントの通知を待っている間もアプリケーションで他の処理が可能にな
ります。API によるイベントの処理の詳細は、『API ガイド』を参照してください。
複数のイベントとの関係の登録
場合によっては、1 つのリクエストハンドルで複数のイベント発生を待ちたいこともありま
す。EVENT INIT では、2 番めの引数に複数のイベント名を指定することができるので、同
時に複数のイベント通知を待つことができます。この場合の EVENT INIT の構文は次のよ
うになります。
EXEC SQL
EVENT INIT request_name (event_name [event_name ...]);
event_name はイベント名で、長さは 15 字以内でなければなりません。また、event_name は
トリガーまたはストアドプロシージャからイベントマネージャに送られるイベント名と同
じでなければなりません。この名前が異なる場合、通知は行われません。たとえば、アプ
リケーションで次の EVENT INIT 文を記述すると、RESPOND_MANY というリクエストハ
ンドルが作成され、“new_order”、“change_order”、“cancel_order” という 3 つのイベントと
の関係が登録されます。
EXEC SQL
EVENT INIT RESPOND_MANY ('new_order', 'change_order',
'cancel_order');
メモ
上では、一意なリクエストハンドルを使って複数のイベントとの関係を登録しています。こ
のほか、EVENT INIT 文を個別に使用して、それぞれ 1 つのリクエストハンドルと 1 つ(ま
たは複数の)のイベントを指定することもできます。ただし、イベント通知の受け取りに
ついては、リクエストハンドルごとに個別に待機しなければなりません。
EVENT WAIT によるイベントの通知の待機
イベントとの関係を登録しても、そのままではイベントの通知を受け取ることはできませ
ん。通知を待つには、EVENT WAIT 文が必要です。この EVENT WAIT 文により、通知の受
け取りの準備ができていることがイベントマネージャに伝えられます。また、通知を受け
取るまでの間、アプリケーションの処理が一時中断されることになります。
受け取り準備の連絡とアプリケーションの処理の一時中断を行いたい場合、EVENT WAIT
の構文は次のようになります。
EXEC SQL
EVENT WAIT request_name;
request_name は、先行の EVENT INIT 文で指定したリクエストハンドルの名前です。
次は、EVENT INIT 文と EVENT WAIT 文を組み合わせた記述例で、この 2 つの文によりリ
クエストハンドルの作成とイベント通知の受け取りが行われます。
11-4 埋 め 込 み S Q L ガ イ ド
イベントに対する応答
EXEC SQL
EVENT INIT RESPOND_NEW ('new_order');
EXEC SQL
EVENT WAIT RESPOND_NEW;
前述のように、EVENT WAIT が実行されると、アプリケーションの処理はイベントの通知
を受け取るまで一時的に中断されます。
メモ
アプリケーションには複数の EVENT WAIT 文を記述できます。EVENT WAIT 文を複数記述
した場合、最初の EVENT WAIT 文でアプリケーションの処理は中断します。処理が再開す
るたびに、次の EVENT WAIT 文でも同様にアプリケーションの処理が中断します。
アプリケーションでイベントの処理が行われている最中に別のイベントが発生したとき
は、そのイベントはイベントマネージャでいったん保持され、アプリケーションが再度待
機状態に入ったときに通知が送られます。
イベントに対する応答
イベントマネージャからの通知を受け取ると、それまで一時中断していたアプリケーション
の処理が再開します。この後、EVENT WAIT 文の後続の処理が実行されることになります。
アプリケーションで 1 つのリクエストハンドルを使って複数のイベントとの関係を登録し
ている場合、どのイベントをアプリケーション側で実際に処理するのか判定する必要があ
ります。この判定には、イベント配列である isc_event[] を使用します。この isc_event[] は、前
処理時に自動的に作成されます。各配列要素は、EVENT INIT の第 2 引数で指定したイベン
ト名に対応しています。また、要素の値は、イベントと同じリクエストハンドルが指定され
ている EVENT WAIT 文が実行された後のイベントの発生回数に一致します。
たとえば、次のコードでは、3 つのイベントとの関係が登録され、いずれかのイベント通知
に対する待機状態に入ります。
EXEC SQL
EVENT INIT RESPOND_MANY ('new_order', 'change_order',
'cancel_order');
EXEC SQL
EVENT WAIT RESPOND_MANY;
この後、“new_order”、“change_order”、“cancel_order” のいずれかのイベントが発生し、処理
に関係しているトランザクションがコミットされると、イベントマネージャによりイベント
の通知がアプリケーションに送られます。これで、アプリケーションの処理が再開します。次
のコードは、アプリケーションで発生したイベントを特定する方法を示します。
for (i = 0; i < 3; i++)
{
if (isc_$event[i] > 0)
{
/* このイベントが発生したため処理します */
. . .
}
}
第 11 章 イベントの操作
11-5
11-6 埋 め 込 み S Q L ガ イ ド
第
章
エラー処理と回復
第 12 章
SQL アプリケーションでは、実行時エラーのトラップと応答、および実行時エラーからの
復旧に関する処理を用意しておかなければなりません。実行時エラーとは、ユーザーがア
プリケーションを使用したときに発生する可能性があるエラーを言います。この章では、
SQL での標準のエラー処理について説明します。この方法は標準なので移植性もあります。
このほか、InterBase 独自のエラー処理についても紹介してあります。
標準のエラー処理
SQL では、SQL 文が実行されるたびに、なんらかのステータスインジケータ(値)が
SQLCODE 変数に返されます。この SQL 変数は、gpre による SQL プログラムの前処理時に
自動的に宣言されます。SQLCODE 変数に格納される値(SQLCODE の値)としては、次の
表のようなものがあります。
表 12.1 SQLCODE の値
値
意味
0
成功
1–99
警告または情報メッセージ
100
。処理すべきデータなし
EOF(ファイルの終わり)
<0
エラー。ステートメントの実行失敗
SQL 処理の後には、SQLCODE の値を必ず検証して、実行時エラーをトラップするととも
に必要な処理を行う必要があります。SQLCODE を検証する場合、次の 3 つの方法がありま
す。検証後、エラー処理を行います。
• WHENEVER 文を使用する方法。この文を使用することで、SQLCODE の検査とエラー発
生時の処理を自動化することができます。
第 12 章 エラー処理と回復
12-1
標準のエラー処理
• SQLCODE を直接検査する方法。この検査は、各 SQL 文のすぐ後で行います。
• WHENEVER 文と直接検査を組み合わせて対処する方法
上の 3 種類の方法は、いずれも短所と長所があります。これらについては、この章におい
て以降の 3 つのトピックで説明します。
WHENEVER 文
WHENEVER 文を使用することで、最小限のコーディングで SQL のエラーを処理すること
ができます。WHENEVER 文では、エラー、警告、EOF(ファイルの終わり)の 3 種類のエ
ラー処理コードを指定できます。エラー処理コードが SQLCODE に格納されるとなんらか
の処理を実行するように、プログラムを記述できます。WHENEVER の構文は次のとおりで
す。
EXEC SQL
WHENEVER {SQLERROR | SQLWARNING | NOT FOUND}
{GOTO label | CONTINUE};
WHENEVER を記述しておいた場合、なんらかのエラー(処理失敗、警告、EOF)が発生し
たときには後続の SQL 文の処理がすべて省略され、label で指定されたコードに処理が移行
します。
このように WHENEVER 文では後続の文の処理が省略されるため、WHENEVER 文は通常、
プログラムの先頭近くに記述するようにします。たとえば、次は、C コードの main() 関数の
先頭に WHENEVER を記述し、SQL エラーをトラップしている例です。
main()
{
EXEC SQL
WHENEVER SQLERROR GOTO ErrorExit;
. . .
Error Exit:
if (SQLCODE)
{
print_error();
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT;
exit(1);
}
}
. . .
print_error()
{
printf("Database error, SQLCODE = %d¥n", SQLCODE);
}
12-2 埋 め 込 み S Q L ガ イ ド
標準のエラー処理
WHENEVER 文には記述によって次の 3 種類があります。それぞれ次のような場合に実行さ
れます。
• WHENEVER に SQLERROR を指定した場合:SQLCODE がマイナスの値のとき、つまり文
の処理が失敗したときに、WHENEVER 文が実行されます。
• WHENEVER に SQLWARNING を指定した場合:SQLCODE の値が 1 から 99 までのいずれ
かの場合、つまり実行されたが、文になんらかの問題が発生した場合、WHENEVER 文が
実行されます。
• WHENEVER に NOT FOUND を指定した場合:SQLCODE の値が 100 のとき、
つまり FETCH
や SELECT の処理で EOF に達したときに、WHENEVER 文が実行されます。
SQLERROR、SQLWARNING、NOT FOUND の機能はそれぞれ独立しており、指定しなかっ
たときは、該当するエラーが発生してもトラップは行われません。たとえば、WHENEVER
NOT FOUND の記述がない場合、FETCH や SELECT により EOF に達したとき(SQLCODE
が 100)でもエラーはトラップされず、プログラムは通常どおり継続されます。
なお、WHENEVER 文に CONTINUE を記述することで、エラーを無視することもできます。
たとえば、次のようになります。
. . .
EXEC SQL
WHENEVER SQLWARNING
CONTINUE;
. . .
上の場合、文は実行されたがなんらかの問題が発生したとき(SQLCODE の値が 1 から 99)
でも無視されます。なお、通常は、警告エラーは検査するのが原則です。
重要
エラー処理ルーチンの先頭に WHENEVER SQLERROR CONTINUE を記述することで、エ
ラー(処理失敗)に対する処理を一時的に無効にすることができます。ただし、この文は
必ず、エラー処理ルーチンの前に記述しなければなりません。WHENEVER SQLERROR
CONTINUE をエラー処理ルーチンの後に記述した場合、エラー処理ルーチン(の SQL 文)
でエラーが発生すると、エラー処理ルーチン自体が呼び出され、無限ループに陥ることが
あります。
WHENEVER 文のスコープ
WHENEVER は、その WHENEVER を記述してあるモジュール(ソースコードファイル)内
の後続の SQL 文に対してだけ有効です。したがって、複数のモジュールで構成されるプロ
グラムでは、各モジュールで WHENEVER 文を記述しなければなりません。
エラー処理ルーチンの変更
エラーの内容(SQLERROR、SQLWARNING、NOT FOUND)が同じであれば、WHENEVER
をもう 1 つ埋め込み、ジャンプ先を指定することで、これまでのエラー処理ルーチンを別
の処理ルーチンに変更することができます。この場合、それまでのエラー処理ルーチンは無
効になります。たとえば、次の文は、エラーの内容が SQLERROR で最初のジャンプ先が
ErrorExit1 でしたが、その後、ジャンプ先を ErrorExit2 に変更している例です。
EXEC SQL
WHENEVER SQLERROR
GOTO ErrorExit1;
第 12 章 エラー処理と回復
12-3
標準のエラー処理
. . .
EXEC SQL
WHENEVER SQLERROR
GOTO ErrorExit2;
. . .
WHENEVER 文に関する制限事項
WHENEVER には、次のような 2 つの制限があります。
• プログラムとは直接関係のないエラーまでトラップしてしまうことがあります。たとえば、
WHENEVER SQLERROR では CHECK 制約に反するデータ入力がトラップされますが、こ
の他必要なデータベースが見つからないときにもエラーとなります。この場合、どちらも
同一のエラー処理ルーチンにジャンプしてしまいます。無効なデータ入力はタイピングの
ミスによるもので、データの再入力で対応できますが、データベースの検索不能は致命的
なエラーで、プログラムの外で措置を取らなければなりません。
• エラーが発生した場所で処理を再開する場合は、記述が難しくなります。たとえば、1 つの
WHENEVER SQLERROR を使用して、CHECK 制約に反するデータ入力をプログラムの各
所でトラップできますが、どの場合も同一のエラー処理ルーチンにジャンプします。このよ
うな場合、ユーザーにとってはデータの再入力が便利ですが、1 つのエラー処理ルーチンで
は、エラーの発生した場所にジャンプして処理を再開するのは、容易ではありません。
もちろん、複雑なエラー処理ルーチンを書くこともできます。たとえば、C や C++ では、手
の込んだ CASE 文を使って SQLCODE を直接検査し、その値にしたがって細かく対応する
ことができます。それでも、エラーが発生した場所で処理を再開するという記述は簡単では
ありません。このため、エラーの発生場所で処理を再開する場合は、通常、SQL 文のたびに
SQLCODE を直接検査するか、複数のエラー処理ルーチンを組み合わせるという方法を使用
します。
SQLCODE の直接検査
WHENEVER では発生するエラーをすべてトラップすることができますが、このほか、SQL
文の後で SQLCODE を直接検査することもできます。この方法の主な利点としては、個々の
状況に応じてエラー処理ルーチンを自由に設計できるという点が挙げられます。
たとえば、次の C コードは、SELECT 文の実行後に、SQLCODE の内容を検査する例です。
この検査で SQLCODE が 0(処理に成功)以外の場合、if 句の中の文が実行されます。ここ
では、if 文は 2 つあり、それぞれ SQLCODE が -1 であるかどうか、また 100 であるかどう
かが検証されます。
SQLCODE が -1 または 100 以外の場合は、エラーメッセージが表示され、プログラムは終
了します。
EXEC SQL
SELECT CITY INTO :city FROM STATES
WHERE STATE = :stat:statind;
if (SQLCODE)
{
if (SQLCODE == –1)
12-4 埋 め 込 み S Q L ガ イ ド
標準のエラー処理
printf("too many records found¥n");
else if (SQLCODE == 100)
printf("no records found¥n");
else
{
printf("Database error, SQLCODE = %d¥n", SQLCODE);
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT;
exit(1);
}
}
printf("found city named %s¥n", city);
EXEC SQL
COMMIT;
EXEC SQL
DISCONNECT;
SQLCODE の直接検査の場合、エラーの発生を検出するために SQL 文ごとに多数のコード
が必要で、これが短所でもあります。一方、記述さえしておけば、関数呼び出しを使ってエ
ラーを処理することもできます。次の C のコードはその例です。
EXEC SQL
SELECT CITY INTO :city FROM STATES
WHERE STATE = :stat:statind;
switch (SQLCODE)
{
case 0:
break; /* エラーなし */
case –1
ErrorTooMany();
break;
case 100:
ErrorNotFound();
break;
default:
ErrorExit(); /* その他のエラーを処理します */
break;
}
. . .
エラー処理に関数呼び出しを使った場合、エラーが修正できるものであれば、実行の再開
を行うこともできます。
第 12 章 エラー処理と回復
12-5
標準のエラー処理
WHENEVER 文と直接検査の組み合わせ
WHENEVER と SQLCODE の直接検査を組み合わせて使用すると、ほとんどのプログラム
で有効なエラー処理が可能です。この方法では、通常のエラーに対しては WHENEVER 文で
対処し、特に重要な場面では WHENEVER を一時的に無効にし、SQLCODE の直接検査を
行います。
この方法では、C コードは次のようになります。
• WHENEVER 文を使って一般的なエラーに対処します。
• CONTINUE 句を使って WHENEVER SQLERROR を無効にしてから、処理を続行します。
• SQLCODE を直接検査します。
• 無効にした WHENEVER SQLERROR を再度有効にします。
main()
{
EXEC SQL
WHENEVER SQLERROR GOTO ErrorExit; /* すべてのエラーをトラップします */
EXEC SQL
WHENEVER SQLWARNING GOTO WarningExit; /* 警告をトラップします */
EXEC SQL
WHENEVER NOT FOUND GOTO AllDone; /* EOF をトラップします */
. . .
EXEC SQL
WHENEVER SQLERROR CONTINUE; /* エラーのトラップを抑制します */
EXEC SQL
SELECT CITY INTO :city FROM STATES
WHERE STATE = :stat:statind;
switch (SQLCODE)
{
case 0:
break; /* エラーなし */
case –1
ErrorTooMany();
break;
case 100:
ErrorNotFound();
break;
default:
ErrorExitFunction(); /* その他のエラーを処理します */
break;
}
EXEC SQL
WHENEVER SQLERROR GOTO ErrorExit; /* リセットして、すべてのエラーをトラッ
プします */
. . .
}
12-6 埋 め 込 み S Q L ガ イ ド
標準のエラー処理
エラー処理のガイドライン
プログラムでエラー処理ルーチンを記述する場合、次のようなガイドラインが適用されま
す。
SQL 文とホスト言語文
エラー処理ルーチンでは、CONNECT を除き、SQL 文と InterBase の関数はすべて記述でき
ます。
エラー処理ルーチンでは、ホスト言語文と関数はすべて記述でき、使用上の制限もありま
せん。
重要
エラー処理ルーチンの先頭に WHENEVER SQLERROR CONTINUE を記述することで、エ
ラー(処理失敗)に対する処理を一時的に無効にすることができます。ただし、この文は
必ず、エラー処理ルーチンの前に記述しなければなりません。WHENEVER SQLERROR
CONTINUE をエラー処理ルーチンの後に記述した場合、エラー処理ルーチン(の SQL 文)
でエラーが発生すると、エラー処理ルーチン自体が呼び出され、無限ループに陥ることが
あります。
ネストされたエラー処理ルーチン
エラー処理ルーチンはネストして記述したり、再帰的呼び出すことができます。ただし、
SQLCODE と InterBase エラーステータス配列の内容が保持できない場合は、このような記
述は避けた方が無難です。
予期しない、または復旧不能のエラーの処理
エラー処理ルーチンでは、通常、復旧可能なエラーについて検査と処理を行います。この
ほか、予期しないか復旧不能なエラーに対しても必ず対応しなければなりません。
このような復旧不能なエラーは、次のコードで対処できます。
. . .
isc_print_sqlerr(SQLCODE, isc_status);
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT;
exit(1);
移植性
InterBase 以外の SQL プログラムとの移植性を考えた場合、エラー処理は WHENEVER 文ま
たは SQLCODE の値の直接検査による処理に限定するのが賢明です。
InterBase では、通常の SQLCODE に比べて、エラーの内容が内部でさらに細かく認識され
ます。つまり、SQLCODE の値が 1 つであっても、その値が複数の種類の内部エラーを示す
こともあります。移植性が問題でなければ、通常のエラー処理に加えて、InterBase 独自の
エラー処理を行うのも有効です。この章の以降のトピックでは、InterBase 独自のエラー処
理について説明します。
第 12 章 エラー処理と回復
12-7
InterBase 独自のエラー処理
InterBase 独自のエラー処理
InterBase では、同じ SQLCODE の値が数種類のエラーを意味することもあります。たとえ
ば、種類の異なるさまざまな InterBase のエラーに、–901 という SQLCODE の値が返されま
す。したがって、他のベンダーの SQL プログラムとの移植性が必要とされない場合は、プ
ログラムでエラーを細かく検査することもできます。この検査には、InterBase のエラース
テータス配列である isc_status を使用します。
isc_status は、ISC_STATUS 型の配列で要素の数は 20 です。宣言は、gpre による前処理時に
自動的に行われます。isc_status では、次の 2 種類のエラー情報が報告されます。
• InterBase のエラーメッセージ
• InterBase のエラー番号
SQLCODE の値が –1、0、100 以外の場合、エラー処理ルーチンでは isc_status を使って次の
ような処理を行うことができます。
• SQL のエラーメッセージと InterBase のエラーメッセージの表示
• SQL のエラーメッセージと InterBase のエラーメッセージをバッファへ取り込み、その後の
処理に利用
• 特定の InterBase のエラーコードのトラップと対応処理
エラーステータス配列である isc_status は、通常、WHENEVER または SQLCODE の直接検
査によるエラーのトラップの後で、その内容を検査します。
エラーメッセージの表示
SQLCODE が –1 未満の値の場合、その値に対応する InterBase のエラーメッセージを表示で
きます。この表示は、エラー処理ルーチンの中に InterBase の isc_print_sqlerror() 関数を記述
することで可能です。なお、isc_print_sqlerror() 関数の宣言は、gpre によるアプリケーション
の前処理時に自動的に行われます。
isc_print_sqlerror() では、SQLCODE の値、その値に対応する SQL のエラーメッセージ、エ
ラーステータス配列である isc_status に格納されている InterBase のエラーメッセージが表
示されます。パラメータは、SQLCODE と isc_status へのポインタの 2 つです。
たとえば、次は isc_print_sqlerror() によるエラー処理ルーチンの例で、エラーが発生した場
合、SQLCODE の値、その値に対応する SQL のエラーメッセージ、InterBase のエラーメッ
セージ(メッセージがある場合)が表示されます。
. . .
EXEC SQL
SELECT CITY INTO :city FROM STATES
WHERE STATE = :stat:statind;
if(SQLCODE)
{
isc_print_sqlerror(SQLCODE, isc_status);
EXEC SQL
ROLLBACK;
12-8 埋 め 込 み S Q L ガ イ ド
InterBase 独自のエラー処理
EXEC SQL
DISCONNECT ALL;
exit(1);
}
. . .
重要
ウィンドウを使用するシステムによっては、画面への直接書き込みは推奨されていないか
禁止されていることがあります。このようなシステムでは、isc_print_sqlerror() の使用は避け
ます。この場合、かわりに、isc_sql_interprete() や isc_interprete() を使用して、メッセージを
バッファに取り込んだ後、表示します。
SQL エラーメッセージの取り込み
SQL のエラーメッセージは isc_print_sqlerror() を使って直接表示できますが、このほか、
isc_sql_interprete() を使ってバッファに取り込むこともできます。このエラーメッセージの取
り込みは、次のような場合に行います。
• 画面への直接書き込みができないウィンドウシステムでアプリケーションを動作させる場
合
• アプリケーションで、すべてのエラーメッセージをログファイルに保存する場合
• エラーメッセージを操作またはフォーマットして表示する場合
isc_sql_interprete() では、SQLCODE、メッセージを格納するバッファへのポインタ、バッファ
の最大サイズ(バイト数)の 3 つの引数を指定します。これで、SQL のエラーメッセージ
を表す文字列が作成され、その文字列がフォーマットされるとともにバッファに格納され
ます。バッファのエラーメッセージは、その後操作が可能になります。なお、バッファサイ
ズは、256 バイトあれば、通常 SQL のエラーメッセージを十分格納できます。
たとえば、次は、SQL のエラーメッセージを err_buf に格納した後、err_buf の内容をログ
ファイルに書き込むコードの例です。
. . .
char err_buf[256]; /* isc_sql_interprete() のエラーメッセージバッファ */
FILE *efile=NULL; /* このコードでは、開かれているファイルへのポインタであるとしま
す */
. . .
EXEC SQL
SELECT CITY INTO :city FROM STATES
WHERE STATE = :stat:statind;
if (SQLCODE)
{
isc_sql_interprete(SQLCODE, err_buf, sizeof(err_buf));
if(efile==NULL) efile=fopen("errors", "w");
fprintf(efile, "%s¥n", err_buf); /* バッファの内容をログファイルに書き込みます
*/
EXEC SQL
ROLLBACK; /* データベースへの変更を元に戻します */
EXEC SQL
第 12 章 エラー処理と回復
12-9
InterBase 独自のエラー処理
DISCONNECT ALL; /* 開かれているデータベースを閉じます */
exit(1); /* エラーフラグを設定して終了します */
}
. . .
上記のように、isc_sql_interprete() を使用して、SQLCODE の値に対応するエラーメッセージ
を取り出してフォーマットすることができます。一方、SQLCODE が –1 未満の値の場合、
InterBase 独自のエラーメッセージを取り出すこともできます。この場合、isc_interprete() 関
数を使用します。ここでも、エラーメッセージは同じくフォーマットされてバッファに格
納されます。
InterBase エラーメッセージの取り込み
InterBase のエラーメッセージは、isc_interprete() を使ってバッファに取り込むことができま
す。isc_interprete() は、次のような場合に使用します。
• 画面への直接書き込みができないウィンドウシステムでアプリケーションを動作させる場
合
• アプリケーションで、すべてのエラーメッセージをログファイルに保存する場合
• エラーメッセージを操作またはフォーマットして表示する場合
重要
isc_interprete() は、SQLCODE が –1 未満の値である場合にのみ使用するようにします。これ
は、SQLCODE が -1 の場合、isc_status のエラー情報が不正確になることがあるためです。
isc_interprete() では、InterBase のエラーメッセージの格納に使用するバッファの場所(割り
当て済み)と、isc_status エラーステータス配列の先頭へのポインタの 2 つの引数を指定し
ます。これで、isc_status から InterBase のエラーメッセージを表す文字列が作成され、その
文字列がフォーマットされるとともにバッファに格納されます。バッファのエラーメッ
セージは、その後の操作が可能です。また、isc_status の先頭を指すポインタが、エラー情
報を表す次のクラスタへ進められます。
isc_interprete() の場合、1 回の呼び出しで取り出され、フォーマットされるエラーメッセージ
は 1 つです。一方、プログラムで発生するエラーによっては、isc_status に複数のエラーメッ
セージが格納されることもあります。したがって、関連するエラーメッセージをすべて取り
出すときは、エラー処理ルーチンで、エラーメッセージが返らなくなるまで isc_interprete()
を繰り返し呼び出すことが必要です。
また、isc_interprete() は isc_status へのポインタを制御することから、直接 isc_status を渡すこ
とはできません。このため、isc_status へのポインタを宣言し、そのポインタを isc_interprete()
に渡すという手順が必要です。
次は、InterBase のエラーメッセージを取り出してログファイルに保存する C のコードの例
です。main() の先頭では、文字列のバッファと isc_status へのポインタの宣言を行っていま
す。なお、ここでは、main() でログファイルが宣言されて開かれており、その後、制御がエ
ラー処理ルーチンに渡されるものとします また、後半のエラー処理ルーチンでは、isc_status
の先頭にポインタを設定した後、isc_interprete() を呼び出しています。
. . .
#include "ibase.h";
. . .
12-10 埋 め 込 み S Q L ガ イ ド
InterBase 独自のエラー処理
main()
{
char msg[512];
ISC_STATUS *vector;
FILE *efile; /* このコードでは、開かれているファイルへのポインタであるとします */
. . .
if (SQLCODE < –1)
ErrorExit();
}
. . .
ErrorExit()
{
vector = isc_status; /* ステータスベクターの先頭に(再)設定します */
isc_interprete(msg, &vector); /* 最初のメッセージを取得します */
fprintf(efile, "%s¥n", msg); /* バッファの内容をログファイルに書き込みます */
msg[0] = '-'; /* 2 番めのメッセージの先頭にハイフンを追加します */
while (isc_interprete(msg + 1, &vector)) /* まだあるか ?*/
fprintf(efile, "%s¥n", msg); /* ある場合はログに書き込みます */
fclose(efile); /* ログを閉じてからプログラムを終了します */
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT ALL;
exit(1); /* 「異常終了」コードを設定してプログラムを終了します */
}
. . .
上の例の処理を順にまとめてみると、次のようになります。
• isc_status エラーステータス配列へのポインタを、isc_status の先頭(ステータスベクターの先
頭のアドレス)に設定します。
• isc_interprete() に対する 1 回めの呼び出しを行い、isc_status(ステータスベクター)の最初の
エラーメッセージを取り出します。
• 最初のエラーメッセージをログファイルに書き込みます。
• WHILE ループで isc_interprete() を繰り返し呼び出し、残りのエラーメッセージを取り出しま
す。残りのエラーメッセージがあったときは、そのエラーメッセージをログファイルに書
き込みます。
• トランザクションによる処理をロールバックします。
• データベースを閉じて、システムリソースを解放します。
第 12 章 エラー処理と回復
12-11
InterBase 独自のエラー処理
InterBase エラーコードの処理
SQLCODE が –1 未満の値の場合、エラーステータス配列 isc_status には InterBase 独自のエラー
メッセージが格納されます。この中には InterBase のエラーコード(isc_convert_error など)も
含まれています。InterBase のエラーコードは、それぞれ InterBase 独自のエラーメッセージを
示す番号に対応しています。この InterBase のエラーコードは、エラー処理ルーチンでトラッ
プすることができ、また個別に対処することもできます。ただし、このエラーコードの扱い
には注意が必要です。
InterBase のエラーコードをトラップして対処する場合、エラー処理ルーチンでは次の手順
で処理を行います。
1
2
SQLCODE を検査し、–1 未満の値であることを確認します。
エラーステータス配列(isc_status)の最初の要素が isc_arg_gds に設定されていること
を確認します。InterBase のエラーコードは、最初の要素が isc_arg_gds に設定されてい
る場合に限りトラップが可能です。なお、C 言語のプログラムでは、エラーステータス
配列の最初の要素は isc_status[0] となります。
エラーステータス配列の最初の要素の値(初期値)が 1 以外の場合は、そのエラース
テータス配列により返されるエラーの処理は行わないでください。
3
ヒント
SQLCODE が –1 未満の値で、かつ isc_status の最初の要素が isc_arg_gds に設定されてい
れば、isc_status の 2 番めの要素(isc_status[1])の中の InterBase のエラーコードを使っ
て分岐し、エラーに対応するためのルーチンを記述します。
InterBase のエラーコードは、ニーモニックとして定義(たとえば、isc_arg_gds)されている
ため、コードでも解読、理解、維持が簡単です。InterBase のエラーコードの定義は ibase.h
ファイルにあります。
エラー処理の例を示す C コード
• isc_print_sqlerror() を使ってエラーメッセージを表示します。
• 6 つの InterBase のエラーのトラップ、取り消し、データ入力、再実行を行います。
• InterBase のエラーコードとして定義されているニーモニックを使って記述を行います。
. . .
int c, jval, retry_flag = 0;
jmp_buf jumper;
. . .
main()
{
. . .
jval = setjmp(jumper);
if (retry_flag)
ROLLBACK;
. . .
}
int ErrorHandler(void)
{
retry_flag = 0; /* 0 にリセットします。再試行しません */
12-12 埋 め 込 み S Q L ガ イ ド
InterBase 独自のエラー処理
isc_print_sqlerror(SQLCODE, isc_status); /* エラーを表示します */
if (SQLCODE < –1)
{
if (isc_status[0] == isc_arg_gds)
{
switch (isc_status[1])
{
case isc_convert_error:
case isc_deadlock:
case isc_integ_fail:
case isc_lock_conflict:
case isc_no_dup:
case isc_not_valid:
printf("¥n Do you want to try again? (Y/N)");
c = getchar();
if (c == 'Y' || c == 'y')
{
retry_flag = 1; /* 再試行フラグを設定します */
longjmp(jumper, 1);
}
break;
case isc_end_arg:/* 実際にはエラーがない場合 */
retry_flag = 1; /* 再試行フラグを設定します */
longjump(jumper, 1);
break;
default:/* すべては処理できないため中止します */
break;
}
}
}
EXEC SQL
ROLLBACK;
EXEC SQL
DISCONNECT ALL;
exit(1);
}
第 12 章 エラー処理と回復
12-13
12-14 埋 め 込 み S Q L ガ イ ド
第
章
動的 SQL
第 13 章
この章では、DSQL アプリケーションの記述方法について説明します。DSQL では、実行時
に SQL 文の作成と実行が可能です。
データベースアプリケーションでは、通常、プログラム作成時にデータベースに対して実
行する SQL 文を指定しておきます。この後、アプリケーションをコンパイルし、アプリケー
ションの SQL 文が設定されます。一方アプリケーションによっては、実行時に用意した文
字列、またはユーザーが入力した文字列をもとに SQL 文を実行できると便利です。このよ
うなアプリケーションでは、実行時に動的に SQL 文を作成したり実行できることが条件と
なります。この能力を備えたアプリケーションを動的 SQL(DSQL)アプリケーションと呼
んでいます。なお、InterBase のユーティリティである isql も DSQL アプリケーションです。
DSQL プログラミングプロセスの概要
DSQL 文の作成と実行は、基本的に次の手順で行います。
• DSQL 処理をサポートしている SQL 文をアプリケーションに埋め込みます。
• ホスト言語のデータ型(変数)やマクロなどを使用して、入力領域と出力領域を用意しま
す。実行時には、この領域(XSQLDA)を介して文とパラメータがやりとりされます。
• アプリケーションに埋め込んだ SQL 文や用意した入出力領域についてプログラミングを行
い、実行時の SQL 文が問題なく処理されるようにします。
これらのステップについて、以降の各節で詳しく説明します。
DSQL に関する制限事項
DSQL には数多くの利点がありますが、次のような制限もあります。
• 一度に 1 つのデータベースにしかアクセスできません。
第 13 章 動的 SQL
13-1
DSQL に関する制限事項
• 動的なトランザクション処理を行うことはできません。トランザクションは、コンパイル
時に宣言しておかなければなりません。
• BLOB データや配列データに動的にアクセスすることはできません。ただし、静的に扱われ
る標準の SQL 文を使って BLOB データと配列データに対してアクセスすることは可能で
す。または、低レベルの API 呼び出しでもアクセスできます。
• データベースの作成は、EXECUTE IMMEDIATE と CREATE DATABASE の組み合わせによ
る処理に限られます。
DSQL アプリケーションでのトランザクション操作の詳細は、13-3 ページの「トランザク
ションの操作」を参照してください。DSQL での BLOB データの処理の詳細は、13-4 ペー
ジの「BLOB データの処理」を参照してください。DSQL での配列データの詳細は、13-4
ページの「配列データの処理」を参照してください。データベースの動的作成の詳細は、
13-4 ページの「データベースの作成」を参照してください。
データベースへのアクセス
標準 SQL 構文では、DSQL アプリケーションは 1 つのソースファイルモジュールについて
1 つのデータベースハンドルしか使用できません。言い換えれば、DSQL アプリケーション
では一度に 1 つのデータベースにしか接続できません。また、データベースハンドルは、
gpre によるアプリケーションの前処理に先立ち、その宣言と初期化を行っておかなければ
なりません。たとえば、次のコードでは、db1 というデータベースハンドルが宣言されると
ともに、0 に初期化されます。
#include "ibase.h"
isc_db_handle db1;
. . .
db1 = 0L;
宣言と初期化が終わると、実行時に、そのデータベースハンドルをデータベースに動的に
割り当てることができます。次は、実行時の割り当ての例です。
char dbname[129];
. . .
prompt_user("Name of database to open: ");
gets(dbname);
EXEC SQL
SET DATABASE db1 = :dbname;
EXEC SQL
CONNECT db1;
. . .
DSQL 文でアクセスできるのは、直前の SET DATABASE コマンドで指定されたデータベー
ス(データベースハンドルを使って指定)に限られます。なお、それまで接続していたデー
タベースを DISCONNECT を使って接続解除すれば、同じデータベースハンドルを使って
別のデータベースに接続できます。この場合、DISCONNECT により自動的にデータベース
ハンドルが NULL に設定されます。たとえば、次は、それまで接続していたデータベース
を DISCONNECT で接続解除した後、0 に初期化し、別のデータベースに接続する場合の記
述例です。
13-2 埋 め 込 み S Q L ガ イ ド
DSQL に関する制限事項
EXEC SQL
DISCONNECT db1;
EXEC SQL
SET DATABASE db1 = 'employee.ib';
EXEC SQL
CONNECT db1;
また、複数のデータベースごとにソースファイルモジュールを作成するという方法を使用
すると、DSQL でも複数のデータベースに接続できます。この場合、データベースへの接続
とデータのアクセスには、低レベルの API 呼び出しを使用します。API 呼び出しの詳細は、
『API ガイド』を参照してください。データベースで使用される SQL 文の詳細は、第 3 章
「データベースの操作」を参照してください。
トランザクションの操作
InterBase では、トランザクション名はすべて gpre によるアプリケーションの前処理時に宣
言が済んでいなければなりません。また、トランザクション名は前処理により設定され、実
行時に変更することはできません。さらに、実行時にトランザクション名を動的に宣言す
ることもできません。
PREPARE、DESCRIBE、EXECUTE、EXECUTE IMMEDIATE などの SQL 文は、オプション
で TRANSACTION 句を付加できます。このような SQL 文では、再コンパイルに先立ち、
TRANSACTION 句でトランザクション名を記述しておくことで、実行時の DSQL 文ととも
に機能するトランザクションを指定することができます。たとえば、次は、t1 というトラン
ザクションを宣言、初期化するとともに、PREPARE に TRANSACTION 句を付加して t1 を
指定しているコード例です。実行時の DSQL 文(この例では、PREPARE により処理される
DSQL 文)では、このトランザクションが機能することになります。
#include "ibase.h"
isc_tr_handle t1;
. . .
t1 = 0L;
EXEC SQL
SET TRANSACTION NAME t1;
EXEC SQL
PREPARE TRANSACTION t1 Q FROM :sql_buf;
PREPARE、DESCRIBE、EXECUTE、EXECUTE IMMEDIATE のいずれかにより処理される
DSQL 文では、その文の中に TRANSACTION 句を使用することはできません。もちろん、
上の例のように、標準の埋め込み SQL では TRANSACTION 句を記述できます。
SET TRANSACTION 文は、PREPARE、DESCRIBE、EXECUTE を使って準備、実行すること
はできませんが、EXECUTE IMMEDIATE を使って処理することは可能です。ただし、次の
ような条件があります。
1
2
それまでのトランザクションがコミット(またはロールバック)済みであること
トランザクションハンドルが NULL に設定されていること
第 13 章 動的 SQL
13-3
DSQL に関する制限事項
この場合の記述例は次のようになります。ここでは、まず、それまでのデフォルトトラン
ザ ク シ ョ ン を コ ミ ッ ト し て NULL に設定した後、EXECUTE IMMEDIATE で SET
TRANSACTION を実行(新規の READ ONLY のトランザクションを起動)しています。
EXEC SQL
COMMIT;
/* デフォルトのトランザクション名を NULL に設定します */
gds__trans = NULL;
EXEC SQL
EXECUTE IMMEDIATE 'SET TRANSACTION READ ONLY';
データベースの作成
DSQL アプリケーションでは、次の手順で新規のデータベースを作成することができます。
1
現在接続されているデータベースをすべて接続解除します。この接続解除により、デー
タベースハンドルは自動的に NULL に設定されます。
2
3
処理に使用する CREATE DATABASE 文を用意します。
CREATE DATABASE 文を EXECUTE IMMEDIATE で実行します。
たとえば、次の文は、現在接続されているデータベースをすべて接続解除し、新規のデー
タベースを作成する例です。データベースハンドルは接続解除により NULL に設定される
ため、そのデータベースを使って後続の DSQL 文で新規のデータベースの作成が可能です。
char *str = "CREATE DATABASE ¥"new_emp.ib¥"";
. . .
EXEC SQL
DISCONNECT ALL;
EXEC SQL
EXECUTE IMMEDIATE :str;
BLOB データの処理
DSQL では、BLOB データを直接処理することはできません。DSQL では BLOB カーソルが
サポートされていないためです。ただし、DSQL アプリケーションでも、API 呼び出しを
使って BLOB データを処理することができます。BLOB データを処理する API 呼び出しの詳
細は、『API ガイド』を参照してください。
配列データの処理
DSQL では、配列データを直接処理することはできません。ただし、DSQL アプリケーショ
ンでも API 呼び出しを使って配列データを処理することができます。API 呼び出しの詳細
は、『API ガイド』を参照してください。
13-4 埋 め 込 み S Q L ガ イ ド
DSQL アプリケーションの記述
DSQL アプリケーションの記述
DSQL アプリケーションは、一般に、実行時まで次の事項が不明な場合に記述します。
• SQL 文で使用する文字列
• 変数の数
• 変数のデータ型
• データベースオブジェクトへの参照
DSQL アプリケーションの記述は、通常の SQL アプリケーションに比べて複雑になるのが
普通です。これは、DSQL の処理のほとんどが、拡張 SQL デスクリプタエリア(XSQLDA)
データ構造体の明示的な割り当てと処理が必要になるためです。DSQL では、この XSQLDA
を介してデータベースとデータのやりとりが行われます。
DSQL で SQL 文を処理する場合、次のような手順で行います。
1
2
3
4
使用する SQL 文が DSQL で処理できるかどうかを検査します。
アプリケーションで SQL 文を文字列として指定する。
必要に応じて、入力パラメータと戻り値に使用する XSQLDA を割り当てる。
適切な DSQL プログラミング手法を使用して、SQL 文を処理します。
DSQL で処理可能な SQL 文
DSQL では、ほとんどの SQL 文の処理が可能です。DSQL で使用可能な SQL 文を以下に示
します。
ALTER DATABASE
ALTER DOMAIN
ALTER EXCEPTION
ALTER INDEX
ALTER PROCEDURE
ALTER TABLE
ALTER TRIGGER
COMMIT
CONNECT
CREATE DATABASE
CREATE DOMAIN
CREATE EXCEPTION
CREATE GENERATOR
CREATE INDEX
CREATE PROCEDURE
CREATE ROLE
CREATE SHADOW
CREATE TABLE
CREATE TRIGGER
CREATE VIEW
DECLARE EXTERNAL FUNCTION
DECLARE FILTER
DELETE
DROP DATABASE
DROP DOMAIN
DROP EXCEPTION
DROP EXTERNAL FUNCTION
DROP FILTER
DROP INDEX
DROP PROCEDURE
DROP ROLE
DROP SHADOW
DROP TABLE
DROP TRIGGER
DROP VIEW
EXECUTE PROCEDURE
第 13 章 動的 SQL
13-5
DSQL アプリケーションの記述
GRANT
INSERT
INSERT CURSOR (BLOB)
REVOKE
ROLLBACK
SELECT
SET GENERATOR
UPDATE
DSQL では、CLOSE、DECLARE、CURSOR、DESCRIBE、EXECUTE、EXECUTE IMMEDIATE、
FETCH、OPEN、PREPARE の ESQL 文を使用できません。
DSQL では、BLOBDUMP、EDIT、EXIT、HELP、INPUT、OUTPUT、QUIT、SET、SET AUTODDL、
SET BLOBDISPLAY、
SET COUNT、
SET ECHO、
SET LIST、
SET NAMES、
SET PLAN、
SET STATS、
SET TERM、SET TIME、SHELL、SHOW CHECK、SHOW DATABASE、SHOW DOMAINS、
SHOW EXCEPTIONS、SHOW FILTERS、SHOW FUNCTIONS、SHOW GENERATORS、SHOW
GRANT、SHOW INDEX、SHOW PROCEDURES、SHOW SYSTEM、SHOW TABLES、SHOW
TRIGGERS、SHOW VERSION、SHOW VIEWS の ISQL コマンドを使用できません。
SQL 文の文字列
DSQL アプリケーションでは、SQL 文が通常の SQL アプリケーションとは異なります。つ
まり、DSQL アプリケーションでは、ユーザーがプロンプトで入力した SQL 文が直接 DSQL
アプリケーションに取り込まれます。これは、isql の場合も同じです。このほか、ユーザー
との対話による応答として、アプリケーションで生成されることもあります(この場合、ア
プリケーションで SQL 文を文字列として記述することが必要)。DSQL では SQL 文にかか
わらず、SQL 文の文字列として指定しなければならず、この文字列が DSQL に渡され処理
が行われることになります。
SQL 文を表す文字列は C の文字列で、DSQL で直接処理されます。したがって、先頭の
EXEC SQL 接頭辞は不要で、末尾にセミコロン(;)を付ける必要もありません。ただし、C
の文字列宣言のターミネータであるセミコロンは付加しなければなりません。たとえば、次
は、SQL 文を文字列として指定している変数宣言の例です。
char *str = "DELETE FROM CUSTOMER WHERE CUST_NO = 256";
SQL 文の文字列の値パラメータ
SQL 文の文字列の中には、式の中で評価の対象となる 1 つの数値または文字の値がパラ
メータとして含まれるものがあります。こういったパラメータは、文字列として指定する
SQL 文の任意の場所に記述できます。ただし、値がデータベースオブジェクトの名前とし
て解釈されるような場所には記述できません。
SQL 文の文字列の中のパラメータは、実行時に定数として、またはプレースホルダとして
渡すこともできます。たとえば、次の文字列は、パラメータである 256 を定数として渡す例
です。
char *str = "DELETE FROM CUSTOMER WHERE CUST_NO = 256";
13-6 埋 め 込 み S Q L ガ イ ド
XSQLDA
上の例では定数は 256 だけですが、パラメータを持つ式を AND などを使って複数組み合わ
せて記述することもできます。この記述方法は、式の値引数が定数ばかりでなく列名の場
合、またはその SQL 文をアプリケーションで 1 回しか実行しない場合などに役立ちます。
パラメータをプレースホルダとして渡す場合は、次のようにステートメント文字列に埋め
込んだ疑問符(?)として値を渡します。
char *str = "DELETE FROM CUSTOMER WHERE CUST_NO = ?";
プレースホルダが記述されている SQL 文が DSQL で処理される場合、疑問符は XSQLDA に
格納されている値に置換されます。したがって、プレースホルダを使って SQL 文を用意し
ておくと、その後は値を変えて何度でもその SQL 文を実行することができます。
プレースホルダは、通常、WHERE 句の検索条件や UPDATE 文の SET 句で使用します。
XSQLDA
DSQL アプリケーションでは、拡張 SQL デスクリプタエリア(XSQLDA)を宣言しなけれ
ばなりません。XSQLDA 構造体は、InterBase の include ディレクトリにある ibase.h ヘッダー
ファイルに定義されています。アプリケーションでは、使用する XSQLDA のインスタンス
を宣言する必要があります。
XSQLDA はホスト言語のデータ構造体で、DSQL で SQL 文が処理される際は、この構造体
を介してデータのデータベースへの移動、またはデータのデータベースからの移動が行わ
れます。XSQLDA には、入力デスクリプタ(入力 XSQLDA)と出力デスクリプタ(出力
XSQLDA)の 2 種類があります。どちらのデスクリプタも XSQLDA 構造体で、構造は同じ
です。
XSQLDA には XSQLVAR というフィールドがあります。この XSQLVAR は非常に重要な
フィールドです。アプリケーションでは、この XSQLVAR が入力パラメータまたは戻り値
(返される列のデータ)の処理に必ず使用されるためです。XSQLVAR も XSQLDA と同様に、
それ自体が構造体で、InterBase の include ディレクトリの中の ibase.h ヘッダーファイルに定
義されています。
アプリケーションでは、事前に XSQLVAR のインスタンスを宣言しておく必要はありませ
ん。ただし、DSQL 文を実行する前に、必要とされる数の XSQLVAR 構造体用の格納領域を
動的に割り当てなければなりません。割り当てた格納領域は、DSQL 文の実行後、必要に応
じて解放します。
次の図は、XSQLDA と XSQLVAR の関係を示したものです。
第 13 章 動的 SQL
13-7
XSQLDA
図 13.1
XSQLDA と XSQLVAR の関係
XSQLDA の 1 つのインスタンス
short version
char sqldaid[8]
ISC_LONG sqldabc
short sqln
short sqld
XSQLVAR sqlvar[1]
XSQLVAR の n 個のインスタンスの配列
1 番めのインスタンス
n 番めのインスタンス
short sqltype
short sqltype
short sqlscale
short sqlscale
short sqlprecision
short sqlprecision
short sqlsubtype
short sqlsubtype
short sqllen
short sqllen
char *sqldata
char *sqldata
short *sqlind
short *sqlind
short sqlname_length
short sqlname_length
char sqlname[METADATALENGTH]
char sqlname[METADATALENGTH]
short relname_length
short relname_length
char relname[METADATALENGTH]
char relname[METADATALENGTH]
short ownname_length
short ownname_length
char ownname[METADATALENGTH]
char ownname[METADATALENGTH]
short aliasname_length
short aliasname_length
char aliasname[METADATALENGTH]
char aliasname[METADATALENGTH]
入力 XSQLDA は、1 つの XSQLDA 構造体と、入力パラメータと同じ数の XSQLVAR 構造体
で構成されます。出力 XSQLDA も、1 つの XSQLDA 構造体と、1 つの SQL 文で返されるデー
タと同じ数の XSQLVAR 構造体で構成されます。XSQLDA とその XSQLDA に含まれる
XSQLVAR 構造体は、メモリ内の連続した領域に一括して割り当てられます。
13-8 埋 め 込 み S Q L ガ イ ド
XSQLDA
XSQLVAR 構造体の数は、PREPARE 文または DESCRIBE 文で判定できます。また、XSQLDA
と XSQLVAR の格納に必要なメモリ領域は、XSQLDA_LENGTH マクロで割り当てることが
できます。XSQLDA_LENGTH マクロの詳細は、13-11 ページを参照してください。
XSQLDA のフィールド
次の表に、XSQLDA 構造体を構成するフィールドその説明を示します。
表 13.1 XSQLDA のフィールド
フィールド定義
説明
short version
XSQLDA 構造体のバージョンを示す。これは SQLDA_CURRENT_VERSION に設
定する。この値は ibase.h で定義されている
char sqldaid[8]
予約
ISC_LONG sqldabc
予約
short sqln
sqlvar 配列の要素(XSQLVAR 構造体)の数。アプリケーションで設定する。ア
プリケーションで XSQLDA 格納用のメモリ領域を割り当てるときは、必ずこ
のフィールドを設定しなければならない(XSQLDA_LENGTH マクロを使用す
る)
short sqld
入力パラメータの数(入力 XSQLDA の場合)または取り出されるデータの数
(出力 XSQLDA の場合)。PREPARE または DESCRIBE の実行時に InterBase に
よって設定される
入力 XSQLDA では、sqld が 0 の場合、SQL 文の入力パラメータがないことを表
す。出力 XSQLDA では、sqld が 0 の場合、SQL 文が SELECT 文ではないことを
表す
XSQLVAR sqlvar
XSQLVAR 構造体の配列。配列の要素の数は、sqln フィールドで示される
XSQLVAR のフィールド
次の表に、XSQLVAR 構造体を構成するフィールドとその説明を示します。
表 13.2 XSQLVAR のフィールド
フィールド定義
説明
short sqltype
入力パラメータまたは取り出されるデータのデータ型を表す。
PREPARE または DESCRIBE の実行時に InterBase によって設定さ
れる
short sqlscale
数値データ型(DECIMAL、NUMERIC)の小数点以下の桁数を示
す。小数点以下の桁数はマイナスの数値で表される。PREPARE
または DESCRIBE の実行時に InterBase によって設定される
short sqlprecision
高精度数値データ型(DECIMAL、NUMERIC)の精度を示す。
PREPARE または DESCRIBE の実行時に InterBase によって設定さ
れる
第 13 章 動的 SQL
13-9
XSQLDA
表 13.2 XSQLVAR のフィールド ( 続き )
フィールド定義
説明
short sqlsubtype
BLOB データのサブタイプを示す。PREPARE または DESCRIBE の
実行時に InterBase によって設定される
short sqllen
sqldata フィールドのデータの最大サイズ(バイト数)。PREPARE
または DESCRIBE の実行時に InterBase によって設定される
char *sqldata
入力 XSQLDA では、選択リスト項目またはパラメータのアドレ
スを指定する。アプリケーションによって設定される
出力 XSQLDA では、選択リスト項目の値を指定する。InterBase
によって設定される
short *sqlind
入力 XSQLDA では、インジケータ変数のアドレスを指定する。
アプリケーションによって設定される
出力 XSQLDA では、FETCH で取り出される選択リスト項目の列
インジケータの値のアドレスを指定する
この値が 0 の場合、列のデータは NULL でないことを示す。–1
の場合、列のデータは NULL であることを示す。InterBase に
よって設定される
short sqlname_length
sqlname
フィールドのデータのサイズ(バイト数)を示す。
DESCRIBE OUTPUT の実行時に InterBase によって設定される
char
sqlname[METADATALENGTH]
short relname_length
BLOB 列の名前を保持する配列を格納する
末尾に null 文字(¥0)は付加されない。DESCRIBE OUTPUT の実
行時に InterBase によって設定される
relname
フィールドのデータのサイズ(バイト数)を示す。
DESCRIBE OUTPUT の実行時に InterBase によって設定される
char
relname[METADATALENGTH]
テーブルの名前を格納する
末尾に null 文字(¥0)は付加されない。DESCRIBE OUTPUT の実
行時に InterBase によって設定される
short ownname_length
ownname フィールドのデータのサイズ(バイト数)を示す。
DESCRIBE OUTPUT の実行時に InterBase によって設定される
char
ownname[METADATALENGTH]
テーブルのオーナー名を格納する
末尾に null 文字(¥0)は付加されない。DESCRIBE OUTPUT の実
行時に InterBase によって設定される
short aliasname_length
aliasname フィールドのデータのサイズ(バイト数)を示す。
DESCRIBE OUTPUT の実行時に InterBase によって設定される
char
aliasname[METADATALENGTH]
列のエイリアスを格納する。エイリアスが存在しない場合は、列
名を格納する
末尾に null 文字(¥0)は付加されない。DESCRIBE OUTPUT の実
行時に InterBase によって設定される
13-10 埋 め 込 み S Q L ガ イ ド
XSQLDA
入力デスクリプタ
入力 XSQLDA(入力デスクリプタ)は、DSQL で処理する SQL 文の文字列にパラメータが
含まれているときに使用します。これは、SQL 文にパラメータが含まれている場合は、事前
にパラメータに対して値を渡してから SQL 文を実行しなければならないためです。パラ
メータがある場合、アプリケーションで DESCRIBE を使ってパラメータの数を指定すると
ともに(この数は XSQLDA の sqld フィールドに格納されます)、各パラメータを XSQLVAR
構造体に割り当てます。たとえば、次の SQL 文の文字列には 2 つのパラメータがあり、し
たがって、アプリケーションでは DESCRIBE を使ってこの数を指定し(sqld が 2)、プレー
スホルダの XSQLVAR への割り当てなどの必要な処理を行います。
char *str = "UPDATE DEPARTMENT SET BUDGET = ? WHERE LOCATION = ?";
これで、SQL 文が実行されたときは、最初の XSQLVAR によって BUDGET 列の値が、2 番
めの XSQLVAR によって LOCATION 列の値が InterBase に渡されることになります。
入力デスクリプタの詳細は、「DSQL のプログラミング手法」を参照してください。
出力デスクリプタ
出力 XSQLDA(出力デスクリプタ)は、クエリーによってその値がアプリケーションに返
される場合に使用します。この場合、戻り値の数は XSQLDA の sqld フィールドに格納され
ます。戻り値は、それぞれ異なる XSQLVAR 構造体に格納されます。また、XSQLDA の sqlvar
フィールドには、最初の XSQLVAR 構造体が格納されます。次は、出力 XSQLDA を必要と
する SQL 文の例です。
char *str = "SELECT * FROM CUSTOMER WHERE CUST_NO > 100";
出力デスクリプタの使い方の詳細は、13-17 ページの「DSQL のプログラミング手法」を
参照してください。
XSQLDA_LENGTH マクロの使い方
XSQLDA_LENGTH マクロは ibase.h に定義されています。このマクロを使用して、入力
XSQLDA ま た は 出 力 XSQLDA に割り当てられるメモリのバイト数を計算できます。
XSQLDA_LENGTH の定義は次のとおりです。
#define XSQLDA_LENGTH (n) (sizeof (XSQLDA) + (n - 1) * sizeof(XSQLVAR))
n は、SQL 文の文字列の中のパラメータの数(入力 XSQLDA)
、または、クエリーで返され
るデータの数(出力 XSQLDA)です。たとえば、次の C 言語の文は XSQLDA_LENGTH マ
クロの使用例で、パラメータが 5 つの XSQLDA、または取り出されるデータの数が 5 つの
XSQLDA に割り当てられるメモリの大きさ(バイト数)が算出されます。
XSQLDA *my_xsqlda;
. . .
my_xsqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(5));
. . .
XSQLDA_LENGTH マクロの使い方の詳細は、13-17 ページの「DSQL のプログラミング
手法」を参照してください。
第 13 章 動的 SQL
13-11
XSQLDA
SQL データ型マクロ定数
InterBase には、
SQL のデータ型と NULL ステータスを示すマクロ定数が用意されています。
このマクロ定数を使用して、XSQLVAR のデータ型を表すことができます。アプリケーショ
ンでパラメータのデータ型を指定する場合、このマクロ定数を使用しなければなりません。
また、SQL 文で選択リストのデータ型を指定するときにも使用します。次の表は、SQL の
データ型、そのデータ型に対応するマクロ定数、C のデータ型または InterBase の typedef
を一覧にしたものです。また、NULL または未知のデータを含むパラメータまたは変数を
示すために sqlind フィールドが使用されているかどうかについても示します。
表 13.3 SQL のデータ型、マクロ式、C のデータ型
sqlind
マクロ式
配列
SQL_ARRAY
配列
SQL_ARRAY + 1
ISC_QUAD
はい
Blob
SQL_BLOB
ISC_QUAD
いいえ
Blob
SQL_BLOB + 1
ISC_QUAD
はい
BOOLEAN
SQL_BOOLEAN
符号付き short
いいえ
BOOLEAN
SQL_BOOLEAN + 1
符号付き short
はい
CHAR
SQL_TEXT
char[ ]
いいえ
CHAR
SQL_TEXT + 1
char[ ]
はい
DATE
SQL_DATE
ISC_DATE
いいえ
DATE
SQL_DATE + 1
ISC_DATE
はい
DECIMAL
SQL_SHORT、 SQL_LONG、
SQL_DOUBLE、または
SQL_INT64
int、long、double、または
いいえ
SQL_SHORT+ 1、
SQL_LONG + 1、
SQL_DOUBLE+ 1、または
SQL_INT64 + 1
int、long、double、または
DOUBLE
PRECISON
SQL_DOUBLE
double
いいえ
DOUBLE
PRECISION
SQL_DOUBLE + 1
double
はい
INTEGER
SQL_LONG
long
いいえ
INTEGER
SQL_LONG + 1
long
はい
FLOAT
SQL_FLOAT
float
いいえ
DECIMAL
13-12 埋 め 込 み S Q L ガ イ ド
C データ型または typedef
が使用さ
れるか ?
SQL データ型
いいえ
ISC_INT64
はい
ISC_INT64
XSQLDA
表 13.3 SQL のデータ型、マクロ式、C のデータ型 ( 続き )
sqlind
SQL データ型
マクロ式
C データ型または typedef
が使用さ
れるか ?
FLOAT
SQL_FLOAT + 1
float
はい
NUMERIC
SQL_SHORT、 SQL_LONG、
SQL_DOUBLE、または
SQL_INT64
int、long、double、または
いいえ
SQL_SHORT + 1、SQL_LONG
int、long、double、または
NUMERIC
+ 1、
ISC_INT64
はい
ISC_INT64
SQL_DOUBLE + 1、または
SQL_INT64 + 1
SMALLINT
SQL_SHORT
short
いいえ
SMALLINT
SQL_SHORT + 1
short
はい
TIME
SQL_TIME
ISC_TIME
いいえ
TIME
SQL_TIME + 1
ISC_TIME
はい
TIMESTAMP
SQL_TIMESTAMP
ISC_TIMESTAMP
いいえ
TIMESTAMP
SQL_TIMESTAMP +1
ISC_TIMESTAMP
はい
VARCHAR
SQL_VARYING
最初の 2 バイトは 文字列の長
さを示す short。
いいえ
残りは char[ ]
VARCHAR
SQL_VARYING + 1
最初の 2 バイトは 文字列の長
さを示す short。
はい
残りは char[ ]
メモ
SQL の DECIMAL と NUMERIC の 2 つのデータ型は、InterBase の内部では SMALLINT、
INTEGER、DOUBLE PRECISION、または 64 ビット整数のいずれかのデータ型で格納され
ます。このため、SQL のデータ型が DECIMAL または NUMERIC であっても、それに対応
す る マ ク ロ 定 数 は 3 種 類 と なります。この場合、isql を使用して、DECIMAL または
NUMERIC の列に実際に対応するマクロ定数を判定することができます。手順は、isql で
テーブルの列の定義を確認し、列のデータがどのデータ型で格納されているかを確認しま
す。確認後、対応するマクロ定数(SQL_SHORT、SQL_LONG、SQL_DOUBLE のいずれか)
を選択します。
パラメータまたは選択リストのデータ型に関する情報は、XSQLVAR 構造体の sqltype フィー
ルドに格納されます。この場合、sqltype フィールドの値で示される情報には次の 2 つがあり
ます。
• パラメータまたは選択リスト項目のデータ型
第 13 章 動的 SQL
13-13
XSQLDA
• sqlind フィールドが使用されているかどうかの情報。 このフィールドが使用されている場
合、その値によりパラメータまたは取り出されるデータが NULL であるか(値は -1)
、また
は NULL でないか(値は 0)がわかります。
たとえば、XSQLVAR 構造体の sqltype フィールドが SQL_TEXT の場合、パラメータまたは
選択リストのデータ型は CHAR で、sqlind フィールドは使用されず、NULL の検査は行われ
ない(というより、理論的には NULL 値の格納が禁止されている)ことを表します。一方、
sqltype フィールドが SQL_TEXT + 1 の場合、パラメータまたは選択リストのデータ型は同じ
く CHAR で、sqlind フィールドが使用され、パラメータまたは選択リストが NULL である
かどうかの検査が可能であることを示します。
ヒント
C の場合は sqltype
& 1 を使ってパラメータや選択リストに NULL が格納されているかど
うかを確認することができます。この sqltype & 1 による評価が 0 の場合、パラメータや選
択リストには NULL は格納されていません。また、評価が 1 の場合、パラメータや選択リ
ストに NULL が格納されていることになります。次は、sqltype & 1 の使用例です。
if (sqltype & 1 == 0)
{
/* NULL を含まないパラメータまたは選択リスト項目 */
}
else
{
/* NULL を含むパラメータまたは選択リスト項目 */
}
PREPARE INTO と DESCRIBE では、デフォルトで type+1 のマクロ関数が返されます。した
がって、PREPARE INTO や DESCRIBE を使った場合は、必ず sqlind フィールドを検査して
値が NULL であるかどうかを確認する必要があります。
可変長文字列データ型の操作
VARCHAR、CHARACTER VARYING、NCHAR VARYING の各データ型は、DSQL では取り
扱いに注意が必要です。この種のデータ型では、データの最初の 2 バイトには文字列の長さ
に関する情報が収められているためです。文字列の実際のバイトは、その残りのデータに
格納されています。
アプリケーションでこのような可変長文字列の抽出と処理のコーディングを避けるには、
SQL マクロ式を使って固定長のデータ型に強制的に変換することができます。可変長デー
タを強制的に固定長に変換する方法については、13-15 ページの「データ型の強制変換」
を参照してください。
アプリケーションで可変長データを直接処理することもできます。それには、まず文字列の
最初の 2 バイトを取り出して文字列自体の長さを判定し、次に文字列をバイト単位で読み
取って NULL 終端のバッファに格納します。
13-14 埋 め 込 み S Q L ガ イ ド
XSQLDA
NUMERIC と DECIMAL のデータ型の扱い
SQL の DECIMAL と NUMERIC の 2 つのデータ型は、InterBase の内部では SMALLINT、
INTEGER、DOUBLE PRECISION、または 64 ビット整数のいずれかのデータ型で格納され
ます。どのデータ型が採用されるかは、列の定義で使用されている DECIMAL または
NUMERIC の 有 効 桁 数 と 小数点以下の桁数によって決まります。 DECIMAL または
NUMERIC の値が、実際に 3 つのうちのどのデータ型でデータベースに格納されているか
は、isql を使ってテーブルの列の定義を確認します。たとえば、定義が NUMERIC であれ
ば、実際のデータは 64 ビット整数で格納されていることになります。
DECIMAL または NUMERIC のデータが、InterBase の内部で SMALLINT または INTEGER
で格納されている場合、その値は整数の形で格納されています。この場合、DSQL でデータ
の取り出しを行うと、XSQLVAR の sqlscale フィールドはマイナスの数値に設定されます。こ
のマイナスの数値は 10 分の 1 を表す係数で、格納されている整数(sqldata で返されます)
をこの係数で割ることによって、NUMERIC または DECIMAL の値が小数点以下の桁数付
きで正しく変換されます。たとえば、sqlscale が –1 の場合、整数を 10 で割ることで、小数点
以下の桁数付きの数値に変換されます。また、–2 では 100、–3 では 1000 で割ることで、正
しく変換されます。
データ型の強制変換
DSQL で入力パラメータまたは選択リストを処理する場合、データ型の変換が必要なことが
あります。この変換処理をデータ型の強制変換と呼んでいます。たとえば、パラメータまた
は取り出されるデータのデータ型が VARCHAR の場合、データ型の強制変換が必要になり
ます。VARCHAR のデータは、最初の 2 バイトに文字列の長さを示す情報が格納されていま
す。その残りが実際の文字列となります。このため、VARCHAR(SQL_VARYING)を CHAR
(SQL_TEXT)に変換すると、データ処理が簡単になります。
データ型の強制変換を行う場合、変換するデータ型に互換性があることが必要です。たとえ
ば、SQL_VARYING から SQL_TEXT へ、SQL_SHORT から SQL_LONG への変換などは互換
性があるため問題ありません。
文字データ型の強制変換
VARCHAR(SQL_VARYING)を CHAR(SQL_TEXT)に変換する場合、パラメータまたは
選 択 リ ス ト 項 目 の XSQLVAR 構造体の sqltype フィールドを変換先の SQL マクロ定数
(SQL_TEXT)に変更します。次の文の var は XSQLVAR 構造体を指すポインタで、この
XSQLVAR の sqltype フィールドは SQL_VARYING です。このフィールドを SQL_TEXT デー
タ型に変換しています。
var->sqltype = SQL_TEXT;
なお、文字データ型を変換したときは、データの格納に必要なメモリ領域を確保しなけれ
ばなりません。この場合、XSQLVAR の sqllen フィールドには変換元のデータサイズに関す
る情報が収められています。これを参考にして、XSQLVAR の sqldata フィールドをデータの
アドレスに設定してください。
第 13 章 動的 SQL
13-15
XSQLDA
数値データ型の強制変換
数 値デ ー タ型 を 他 のデ ー タ型に変換する場合、パラメータまたは選択リスト項目の
XSQLVAR 構造体の sqltype フィールドを変換先の SQL マクロ定数に変更します。次の文の
var は、XSQLVAR 構 造 体 を指すポインタで、この XSQLVAR の sqltype フィールドは
SQL_SHORT データ型です。この項目を SQL_LONG データ型に変換しています。
var->sqltype = SQL_LONG;
重要
桁数の大きいデータ型を桁数の小さいデータ型に強制変換してはなりません。 データが失
われる原因となります。
NULL インジケータの設定
パラメータまたは取り出されるデータの値が NULL のこともあります。この場合、sqlind
フィールドを使用して、引数または取り出されるデータの NULL ステータス(値が NULL
かどうか)を調べることができます。なお、sqlind フィールドの値を格納するには、メモリ
領域の確保が必要です。
入力 XSQLDA では、値が NULL の場合、sqlind フィールドを –1 に設定します。NULL でな
い場合、sqlind フィールドを 0 に設定します。
出力 XSQLDA では、sqlind フィールドが –1 の場合、データは NULL であることを示します。
それ以外のときは、データは NULL でないことを示します。
数値データの配置(アラインメント)
一般に、データ型が数値の変数は、コンパイラによりメモリ境界に規則的に並ぶように割
り付けられます(アラインメントされる)。これに対して、XSQLDA 構造体や XSQLVAR 構
造体で見られるように、動的に割り当てられたバッファに数値データが格納される場合は、
バッファ中に規則正しくアラインメントされるように注意する必要があります。
RISC プロセッサの場合など、プラットフォームによっては、動的に割り当てられた構造体
の数値データがメモリの中で必ず正しくアラインメントされるように注意しなければなり
ません。アラインメントは、データのデータ型とプラットフォームによって異なります。
たとえば、Sun SPARCstation では、16 ビット整数は 2 で割れるアドレスに格納しなければ
なりません。また、32 ビットの場合、4 で割れるアドレスに格納することが必要です。こ
のように、通常、システムにより所定のアラインメントの値が決まっており、このアライ
ンメントの値で先頭のバイトのアドレスが割れる場合、データは正しくアラインメントし
ていることになります。アラインメントの要件はシステムやコンパイラによって異なるこ
とがあるため、付属のマニュアルを参照してください。
なお、数値データのアラインメントについては便利な一般法則があります。これは、デー
タ型のサイズが、必ずそのデータ型のアラインメントの値であるというものです。式を使っ
て表すと、データ型を T とした場合、(T) のサイズが n に等しければ、n で割り切れるアド
レスが T のアラインメントのためのアドレスということになります。したがって、次のマ
クロの式を使用すると、データのアラインメントが可能になります。
#define ALIGN(ptr, n) ((ptr + n - 1) & ~(n - 1))
上の例で、ptr は char のポインタです。
次のコードは、ALIGN マクロの使用例です。
13-16 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
char *buffer_pointer, *next_aligned;
next_aligned = ALIGN(buffer_pointer, sizeof(T));
DSQL のプログラミング手法
文字列としての SQL 文を処理する場合の DSQL プログラミング手法には、全部で 4 つの種
類があります。どの DSQL プログラミング手法が適切かは、SQL 文の内容によって異なり
ます。また、SQL 文にプレースホルダ(入力パラメータ)があるかどうかも、選択の要因
となります。次の表は、使用すべき DSQL プログラミング手法を示したものです。
表 13.4 SQL 文の文字列と推奨される処理方法
クエリーか ?
プレースホルダがあるか ?
使用するプログラミング手法
いいえ
いいえ
手法 1
いいえ
はい
手法 2
はい
いいえ
手法 3
はい
はい
手法 4
手法 1:パラメータのない非クエリー SQL 文
SQL 文がクエリーではなく、プレースホルダパラメータもない場合、次の 2 とおりの処理
方法があります。
• EXECUTE IMMEDIATE を使って準備と実行を一括して行います。通常、SQL 文の実行が
一度限りのときに使用します。
• PREPARE を使って SQL 文の分析(用意)を行うとともに SQL 文に名前を付け、その後、
EXECUTE で SQL 文を実行します。通常、その SQL 文をアプリケーションで何回も実行す
るときに使用します。
EXECUTE IMMEDIATE による実行
1 EXECUTE IMMEDIATE を使って SQL 文を実行する場合、手順は次のようになります。
EXECUTE IMMEDIATE は、実行が一度限りの場合に使用します。
2
ユーザーからの SQL 文の入力を求めます。または、処理する SQL 文の文字列を作成し
ます。以下の文は、SQL 文の文字列を作成します。
char *str = "UPDATE DEPARTMENT SET BUDGET = BUDGET * 1.05";
3
EXECUTE IMMEDIATE で SQL 文の文字列を分析し、実行します。
EXEC SQL
EXECUTE IMMEDIATE :str;
メモ
EXECUTE IMMEDIATE では変数のかわりに文字列定数も使用できます。
次に例を示します。
EXEC SQL
EXECUTE IMMEDIATE
'UPDATE DEPARTMENT SET BUDGET = BUDGET * 1.05';
第 13 章 動的 SQL
13-17
DSQL のプログラミング手法
PREPARE と EXECUTE による実行
PREPARE と EXECUTE を使って SQL 文の文字列を何度か実行する場合、手順は次のように
なります。
1
ユーザーからの SQL 文の入力を求めます。または、処理する SQL 文の文字列を作成し
ます。以下の文は、SQL 文の文字列を作成します。
char *str = "UPDATE DEPARTMENT SET BUDGET = BUDGET * 1.05";
2
PREPARE を使って SQL 文の文字列を分析し、SQL 文に名前を付けます。この名前は、
後続の EXECUTE で使用します。
EXEC SQL
PREPARE SQL_STMT FROM :str;
上の例で、SQL_STMT は分析対象の SQL 文の文字列に割り当てられる名前です。
3
EXECUTE を使って名前を付けた SQL 文を実行します。次の文は、SQL_STMT という名
前の SQL 文を実行する例です。
EXEC SQL
EXECUTE SQL_STMT;
メモ
PREPARE では変数のかわりに文字列定数も使用できます。次に例を示します。
EXEC SQL
PREPARE SQL_STMT FROM
'UPDATE DEPARTMENT SET BUDGET = BUDGET * 1.05';
作成したステートメント文字列は、アプリケーション内で必要に応じて何度も使用でき
ます。
手法 2:パラメータのある非クエリー SQL 文
SQL 文がクエリーではなく、プレースホルダパラメータがある場合、次の 2 段階の手順で
処理を行います。
1
2
SQL 文のパラメータを処理するための入力 XSQLDA を作成します。
パラメータのある SQL 文の文字列を用意し、実行します。
入力 XSQLDA の作成
SQL 文にプレースホルダパラメータがある場合、そのプレースホルダが実際のデータに置
き換えられた後、SQL 文の文字列が実行されるという流れで処理が行われます。この場合、
パラメータのある SQL 文の文字列を作成したときは、パラメータの値は不定です。このた
め、入力 XSQLDA を作成し、この入力 XSQLDA を介して SQL 文 SQL 文 SQL 文の実行時に
パラメータの値を渡すという処理が必要になります。入力 XSQLDA の作成は、次の手順で
行います。
1
入力 XSQLDA を格納するための変数を宣言します。この入力 XSQLDA によってパラ
メータが処理されます。たとえば、in_sqlda という名前の XSQLDA の変数を宣言する場
合は、次のようになります。
XSQLDA *in_sqlda;
13-18 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
2
宣言した XSQLDA の XSQLVAR 構造体にアクセスするための変数を宣言します。
XSQLVAR *var;
なお、この変数(ポインタ)の宣言はオプションで必ずしも必要ではありませんが、こ
の変数を宣言することで、後続の文での XSQLVAR 構造体の参照が簡単になります。
3
XSQLDA_LENGTH マクロを使って XSQLDA を格納するためのメモリを割り当てます。
たとえば、in_sqlda のメモリを割り当てる場合、記述は次のようになります。
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
上の文では、XSQLVAR 10 個分の領域を割り当てています。つまり、in_sqlda には、10
個のパラメータを格納するだけの領域が与えられたことになります。
4
XSQLDA の version フィールドに SQLDA_CURRENT_VERSION を設定し、sqln フィール
ドに XSQLVAR 構造体の割り当て数を設定します。
in_sqlda_version = SQLDA_CURRENT_VERSION;
in_sqlda->sqln = 10;
パラメータのある SQL 文の文字列の作成と実行
以上の要領でパラメータを格納する準備ができたら、処理対象となる SQL 文の文字列を作
成します。また、ローカル変数を使用して、文字列中のプレースホルダパラメータをそれぞ
れ、XSQLVAR 構造体の sqldata フィールドに割り当てます。
パラメータのある非クエリーの SQL 文の文字列の作成と実行は、次の手順で行います。
1
ユーザーからの SQL 文の文字列の入力を求めます。または、処理する SQL 文の文字列
を作成します。たとえば、次の文は、プレースホルダパラメータがある SQL 文の文字列
を作成する例です。
char *str = "UPDATE DEPARTMENT SET BUDGET = ?, LOCATION = ?";
上の SQL 文にはパラメータが 2 つあります。これらは、それぞれ BUDGET 列の値と
LOCATION 列の値に相当します。
2
PREPARE を使って SQL 文の文字列を分析し、SQL 文に名前を付けます。この名前は、
後続の DESCRIBE および EXECUTE で使用します。
EXEC SQL
PREPARE SQL_STMT FROM :str;
SQL_STMT は、分析対象の SQL 文の文字列に割り当てられる名前です。
3
DESCRIBE INPUT を使用して、入力 XSQLDA に SQL 文中のパラメータに関する情報を
入力します。
EXEC SQL
DESCRIBE INPUT SQL_STMT USING SQL DESCRIPTOR in_sqlda;
4
XSQLDA の sqln フィールドの値と XSQLDA の sqld フィールドの値を比較し、パラメー
タを全部格納できるだけの数の XSQLVAR が割り当てられているかどうかを検査しま
す。この場合、sqln フィールドの値は、sqld フィールドの値と同じか大きくなければな
りません。sqln フィールドの値が sqld フィールドの値より小さいときは、先に XSQLDA
に割り当てた領域をいったん解放し、パラメータの数(sqld フィールドで示されます)
に見合うだけの領域を再度割り当てます。また、sqln と version を再設定し、もう一度
DESCRIBE INPUT を実行します。この処理の記述は次のようになります。
第 13 章 動的 SQL
13-19
DSQL のプログラミング手法
if (in_sqlda->sqld > in_sqlda->sqln)
{
n = in_sqlda->sqld;
free(in_sqlda);
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
in_sqlda->sqln = n;
in_sqlda->version = SQLDA_CURRENT_VERSION;
EXEC SQL
DESCRIBE INPUT SQL_STMT USING SQL DESCRIPTOR in_sqlda;
}
5
XSQLDA 内の各 XSQLVAR パラメータ構造体を処理します。各パラメータ構造体の処理
は、次の 4 段階に分かれます。
• パラメータのデータ型を強制変換する(オプション)
。
• データ(XSQLVAR の sqldata フィールドによって示される)を格納するローカル領
域を確保する。この処理は、実行時にローカル変数の領域の割り当てが行われてい
ない場合に限り必要です。次に、ローカル変数の格納領域を動的に割り当てる例が
あるため、そちらを参考にしてください。
• パラメータに値を設定する。値は、パラメータに定義されているデータ型で設定し
なければなりません。この処理は必須です。
• パラメータに NULL 値インジケータを設定する。
以上の処理を記述すると、次のようなコードになります。ここでは、XSQLDA である
in_sqlda の中の各 XSQLVAR 構造体をループで処理しています。
for (i=0, var = in_sqlda->sqlvar; i < in_sqlda->sqld; i++, var++)
{
/* ここで、XSQLVAR パラメータ構造体を処理する
パラメータ構造体は、var で示す */
dtype = (var->sqltype & ~1) /* ここで、NULL フラグを削除します */
switch(dtype)
{
case SQL_VARYING:/* SQL_TEXT に強制変換します */
var->sqltype = SQL_TEXT;
/* ローカル変数の格納領域を割り当てます */
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
. . .
break;
case SQL_TEXT:
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
/* パラメータに値を設定します */
. . .
break;
case SQL_LONG:
var->sqldata = (char *)malloc(sizeof(long));
/* パラメータに値を設定します */
13-20 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
*(long *)(var->sqldata) = 17;
break;
. . .
} /* switch 文の終わり */
if (var->sqltype & 1)
{
/* NULL ステータスを保持する変数を割り当てる */
var->sqlind = (short *)malloc(sizeof(short));
}
}
/* for ループの終わり */
データ型の強制変換と NULL インジケータについては、13-15 ページの「データ型の
強制変換」を参照してください。
6
EXECUTE を使って名前を付けた SQL 文を実行します。入力 XSQLDA の中のパラメータ
(XSQLVAR 構造体)は、USING SQL DESCRIPTOR 句を使って参照します。次は、
SQL_STMT という名前の SQL 文の文字列を実行する場合の文です。
EXEC SQL
EXECUTE SQL_STMT USING SQL DESCRIPTOR in_sqlda;
SQL 文の文字列の再実行
パラメータ付きの非クエリー 文の文字列を作成したら、その SQL 文をアプリケーションで
繰り返し使用できます。この場合、パラメータ(入力 XSQLDA)に新しいデータを入れ、
NULL インジケータを設定します。
パラメータへの値の入力と NULL インジケータの設定は、この章の「パラメータのある SQL
文の文字列の作成と実行」の 3 ~ 5 の手順と同じです。
手法 3:パラメータのないクエリー SQL 文
SQL 文の文字列がクエリーでパラメータがない場合、次の 3 段階の手順で処理を行います。
1
出力 XSQLDA を作成します。この出力 XSQLDA によって、クエリーの実行時に取り出
される選択リスト項目を処理します。
2
3
SQL 文の文字列(クエリー)を用意します。
カーソルを使って SQL 文を実行するとともに、出力 XSQLDA から選択リストを取り出
します。
出力 XSQLDA の作成
クエリーでは、通常、1 つ以上の行が返されます。この行に含まれる列のデータを選択リス
トと呼んでいます(記述によってはデータが複数のこともある)。ただし、SQL 文の文字列
の作成時には、返されるデータの数は不定なため、出力 XSQLDA を作成し、実行時、この
出力 XSQLDA にいったん選択リスト項目を格納するという処理が必要になります。出力
XSQLDA の作成は、次の手順で行います。
第 13 章 動的 SQL
13-21
DSQL のプログラミング手法
1
出力 XSQLDA を格納するための変数を宣言する。これは、取得する行の各列にある
データを保存するために必要です。次の宣言は、out_sqlda という XSQLDA を作成しま
す。
XSQLDA *out_sqlda;
2
宣言した XSQLDA の XSQLVAR 構造体にアクセスするための変数を宣言します。
XSQLVAR *var;
なお、この変数(ポインタ)の宣言はオプションで必ずしも必要ではありませんが、こ
の変数を宣言することで、後続の文での XSQLVAR 構造体の参照が簡単になります。
3
XSQLDA_LENGTH マクロを使って XSQLDA を格納するためのメモリを割り当てます。
たとえば、out_sqlda のメモリを割り当てる場合、記述は次のようになります。
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
上の文では、XSQLVAR 構造体 10 個分の領域を割り当てています。つまり、out_sqlda
には、10 個の選択リストを格納するだけの領域が与えられます。
4
XSQLDA の version フィールドに SQLDA_CURRENT_VERSION を設定します。また、
sqln フィールドを、割り当てられた XSQLVAR 構造体の数に設定します。
out_sqlda->version = SQLDA_CURRENT_VERSION;
out_sqlda->sqln = 10;
クエリー SQL 文の文字列の用意
以上の要領でデータを格納する XSQLDA の作成ができたら、クエリー SQL 文の文字列を作
成し、SQL 文の文字列の実行に備えます。実行すると、InterBase によりクエリーの記述に
したがって行が取り出され、選択リスト項目が作成されます。
クエリーの SQL 文の文字列は、次のように作成します。
1
ユーザーに SQL 文の文字列の入力を求めます。または、クエリー SQL 文の文字列を作
成します。次の文は、クエリー SQL 文の文字列を作成する例です。
char *str = "SELECT * FROM CUSTOMER";
この文では、SELECT の右にアスタリスク(*)を記述しています。このアスタリスク
は、テーブルのすべての列を表すワイルドカード記号です。したがって、このクエリー
では、テーブルのすべての列と同じ数のデータが返されます。
2
PREPARE を使って SQL 文の文字列を分析するとともに SQL 文に名前を付けます。この
名前は、後続の DESCRIBE や EXECUTE などの文で使用します。
EXEC SQL
PREPARE SQL_STMT FROM :str;
SQL_STMT は、分析対象の SQL 文の文字列に割り当てられる名前です。
3
DESCRIBE OUTPUT を使用して、SQL 文から返されるデータの情報を出力 XSQLDA に
渡します。
EXEC SQL
DESCRIBE OUTPUT SQL_STMT INTO SQL DESCRIPTOR out_sqlda;
13-22 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
4
XSQLDA の sqln フィールドの値と XSQLDA の sqld フィールドの値を比較し、クエリー
で返される選択リストを全部格納できるだけの数の XSQLVAR が割り当てられているか
どうかを検査します。ここで、sqln フィールドの値が sqld フィールドの値より小さいと
きは、先に XSQLDA に割り当てた領域をいったん解放し、選択リストの数(sqld
フィールドで示されます)に見合うだけの領域を再度割り当てます。また、sqln と
version を再設定し、もう一度 DESCRIBE OUTPUT を実行します。この処理の記述は次
のようになります。
if (out_sqlda->sqld > out_sqlda->sqln)
{
n = out_sqlda->sqld;
free(out_sqlda);
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
out_sqlda->sqln = n;
out_sqlda->version = SQLDA_CURRENT_VERSION;
EXEC SQL
DESCRIBE OUTPUT SQL_STMT INTO SQL DESCRIPTOR out_sqlda;
}
5
データを表す XSQLVAR 構造体をそれぞれ処理します。次の手順にしたがいます。
• データのデータ型を強制変換する(オプション)
。
• データ(XSQLVAR の sqldata フィールドによって示される)を格納するローカル領
域を確保する。この処理は、実行時にローカル変数の領域の割り当てが行われてい
ない場合に限り必要です。次に、ローカル変数の格納領域を動的に割り当てる例が
あるため、そちらを参考にしてください。
• パラメータに NULL 値インジケータを設定する。
以上の処理を記述するコードは次のとおりです。ここでは、XSQLDA 構造体 out_sqlda
の中の各 XSQLVAR 構造体をループで処理しています。
for (i=0, var = out_sqlda->sqlvar; i < out_sqlda->sqld; i++, var++)
{
dtype = (var->sqltype & ~1) /* ここで、フラグビットを削除します */
switch (dtype)
{
case SQL_VARYING:
var->sqltype = SQL_TEXT;
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen + 2);
break;
case SQL_TEXT:
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
break;
case SQL_LONG:
var->sqldata = (char *)malloc(sizeof(long));
break;
. . .
/* 残りの型を処理します */
第 13 章 動的 SQL
13-23
DSQL のプログラミング手法
} /* switch 文の終わり */
if (sqltype & 1)
{
/* NULL ステータスを保持する変数を割り当てます */
var->sqlind = (short *)malloc(sizeof(short));
}
}
/* for ループの終わり */
データ型の強制変換と NULL インジケータについては、13-15 ページの「データ型の
強制変換」を参照してください。
SQL 文の文字列のカーソルによる実行
クエリー SQL 文の文字列の準備ができたら、カーソルを使って SQL 文を実行し選択リスト
を取り出します。なお、InterBase でのカーソル宣言はすべてコンパイルの時点で固定され
るとともに、埋め込んだ文もアプリケーションに挿入されます。したがって、DSQL アプリ
ケーションを作成する場合は、事前に使用されると思われるカーソルを想定し宣言してお
く必要があります。
カーソルを使って SQL 文を実行する場合は、ループ構造を使用します。この場合、まず 1
行だけ取り出し、その行について選択リスト項目(列のデータ)を処理します。その後、同
様に次の行の取り出しと選択リストの処理を行います。
カーソルによる SQL 文の実行と行の取り出しと選択リスト項目の処理は、次の手順で行います。
1
SQL 文の文字列の実行に必要なカーソルを宣言します。たとえば、次は、SQL_STMT と
いう名前の SQL 文の文字列で使用するカーソルとして DYN_CURSOR を宣言している
例です。
EXEC SQL
DECLARE DYN_CURSOR CURSOR FOR SQL_STMT;
2
宣言したカーソルを開きます。
EXEC SQL
OPEN DYN_CURSOR;
SQL 文の文字列は、カーソルを開くと同時に実行されるとともに、行のアクティブ
セットが作成されます。カーソルとアクティブセットの詳細は、第 6 章「データ処理」
を参照してください。
3
ループを使って行を 1 行ずつ取り出し、各行について選択リスト(列のデータ)を処理
します。たとえば、次は、DYN_CURSOR カーソルを使って行を 1 行ずつ取り出すとと
もに、各行について選択リスト項目の処理を行っているループの例です。ここでは、ア
プリケーション独自の関数(process_column())を使って行の列のデータを処理していま
す。
while (SQLCODE == 0)
{
EXEC SQL
FETCH DYN_CURSOR USING SQL DESCRIPTOR out_sqlda;
if (SQLCODE == 100)
break;
for (i = 0; i < out_sqlda->sqld; i++)
13-24 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
{
process_column(out_sqlda->sqlvar[i]);
}
}
上の例の process_column() 関数は、返された各選択リスト項目を処理します。次の概略
コードは、このような関数の設定方法を示します。
void process_column(XSQLVAR *var)
{
/* NULL 値かどうかをテストします */
if ((var->sqltype & 1) && (*(var->sqlind) = -1))
{
/* NULL 値を処理します */
}
else
{
/* データを処理します */
}
. . .
}
4
全部の行の取り出しが完了したら、カーソルを閉じます。
EXEC SQL
CLOSE DYN_CURSOR;
クエリー SQL 文の文字列の再実行
パラメータのないクエリー 文の文字列を作成したら、それをアプリケーションで繰り返し
使用できます。この場合、カーソルを閉じてから、もう一度開きます。
カーソルを再度開いて選択リスト項目を処理するには、この章の「クエリー SQL 文の文字
列のカーソルによる実行」のステップ 2 ~ 4 を繰り返してください。
手法 4:パラメータのあるクエリー SQL 文
SQL 文がクエリーでプレースホルダパラメータがある場合、SQL クエリー 文の文字列の処
理は次の手順で行います。
1
入力 XSQLDA を作成します。この入力 XSQLDA は、SQL 文の文字列のパラメータを処
理するために使用します。
2
出力 XSQLDA を作成します。この出力 XSQLDA によって、クエリーの実行時に取り出
される選択リスト項目を処理します。
3
4
パラメータのあるクエリー SQL 文の文字列を用意します。
カーソルを使用して、入力 XSQLDA に格納されているパラメータの値をもとに SQL 文
を実行するとともに、出力 XSQLDA から選択リスト項目を取り出します。
第 13 章 動的 SQL
13-25
DSQL のプログラミング手法
入力 XSQLDA の作成
SQL 文にプレースホルダパラメータがある場合、そのプレースホルダが実際のデータに置
き換えられた後、SQL 文の文字列が実行されるという流れで処理が行われます。この場合、
パラメータのある SQL 文の文字列を作成したときは、パラメータの値は不定です。このた
め、入力 XSQLDA を作成し、この入力 XSQLDA を介して SQL 文の実行時にパラメータの
値を渡すという処理が必要になります。入力 XSQLDA の作成は、次の手順で行います。
1
入力 XSQLDA を格納するための変数を宣言します。この入力 XSQLDA によってパラ
メータが処理されます。たとえば、in_sqlda という名前の XSQLDA の変数を宣言する場
合は、次のようになります。
XSQLDA *in_sqlda;
2
宣言した XSQLDA の XSQLVAR 構造体にアクセスするための変数を宣言します。
XSQLVAR *var;
なお、この変数(ポインタ)の宣言はオプションで必ずしも必要ではありませんが、こ
の変数を宣言することで、後続の文での XSQLVAR 構造体の参照が簡単になります。
3
XSQLDA_LENGTH マクロを使って XSQLDA を格納するためのメモリを割り当てます。
たとえば、in_slqda のメモリを割り当てる場合、記述は次のようになります。
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
上の文では、XSQLVAR 構造体 10 個分の領域を割り当てています。つまり、in_sqlda に
は、10 個の入力パラメータを格納するだけの領域が与えられることになります。構造体
が割り当てられると XSQLVAR ごとに sqldata フィールドに値が設定されます。
4
XSQLDA の version フィールドに SQLDA_CURRENT_VERSION を設定します。また、
sqln フィールドを、割り当てられた XSQLVAR 構造体の数に設定します。
in_sqlda->version = SQLDA_CURRENT_VERSION;
in_sqlda->sqln = 10;
出力 XSQLDA の作成
SQL 文の文字列を作成するときは、どのくらいの数のデータが返されるかは事前に判定す
ることはできません。このため、出力 XSQLDA を作成し、実行時、この出力 XSQLDA に
いったんデータを格納するという処理が必要になります。出力 XSQLDA の作成は、次の手
順で行います。
1
入力 XSQLDA を格納するための変数を宣言します。この入力 XSQLDA によってパラ
メータが処理されます。たとえば、out_sqlda という名前の XSQLDA の変数を宣言する場
合は、次のようになります。
XSQLDA *out_sqlda;
2
宣言した XSQLDA の XSQLVAR 構造体にアクセスするための変数を宣言します。
XSQLVAR *var;
なお、この変数(ポインタ)の宣言はオプションで必ずしも必要ではありませんが、こ
の変数を宣言することで、後続の文での XSQLVAR 構造体の参照が簡単になります。
3
XSQLDA_LENGTH マクロを使って XSQLDA を格納するためのメモリを割り当てます。
たとえば、out_sqlda のメモリを割り当てる場合、記述は次のようになります。
13-26 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(10));
上の文では、XSQLVAR 構造体 10 個分の領域を割り当てています。つまり、out_sqlda
には、10 個の選択リストを格納するだけの領域が与えられます。
4
XSQLDA の version フィールドに SQLDA_CURRENT_VERSION を設定します。また、
sqln フィールドを、割り当てられた XSQLVAR 構造体の数に設定します。
out_sqlda->version = SQLDA_CURRENT_VERSION;
out_sqlda->sqln = 10;
パラメータを持つクエリー SQL 文の文字列の用意
SQL 文の文字列のパラメータを格納する入力 XSQLDA と、文を実行したときに返される選
択リスト項目を格納する出力 XSQLDA が作成できたら、その SQL 文の文字列を実行するこ
とができます。SQL 文の文字列の準備が整うと、InterBase は SQL 文の文字列内のプレース
ホルダパラメータを、使用される実パラメータに関する情報に置き換えます。パラメータに
関する情報を入力 XSQLDA に割り当てないと(多くの場合は調整も行わないと)、SQL 文
は実行できません。SQL 文の文字列を実行すると、InterBase は出力 XSQLDA に選択リスト
項目を格納します。
パラメータのあるクエリー SQL 文の文字列は、次の手順で作成します。
1
ユーザーからの SQL 文の文字列の入力を求めます。または、処理する SQL 文の文字列
を作成します。たとえば、次の文は、プレースホルダパラメータがある SQL 文の文字列
を作成する例です。
char *str = "SELECT * FROM DEPARTMENT WHERE BUDGET = ?, LOCATION = ?";
上の SQL 文にはパラメータが 2 つあります。これらは、それぞれ BUDGET 列の値と
LOCATION 列の値に相当します。
2
PREPARE を使って SQL 文の文字列を準備し、SQL 文に名前を付けます。この名前は、
後続の DESCRIBE および EXECUTE で使用します。
EXEC SQL
PREPARE SQL_STMT FROM :str;
SQL_STMT は、分析対象の SQL 文の文字列に割り当てられる名前です。
3
DESCRIBE INPUT を使用して、入力 XSQLDA に SQL 文中のパラメータに関する情報を
入力します。
EXEC SQL
DESCRIBE INPUT SQL_STMT USING SQL DESCRIPTOR in_sqlda;
4
XSQLDA の sqln フィールドの値と XSQLDA の sqld フィールドの値を比較し、パラメー
タをすべて格納できるだけの数の XSQLVAR が割り当てられているかどうかを検査しま
す。sqln フィールドの値が sqld フィールドの値より小さいときは、先に XSQLDA に割
り当てた領域をいったん解放し、パラメータの数(sqld フィールドで示されます)に見
合うだけの領域を再度割り当てます。また、sqln と version を再設定し、もう一度
DESCRIBE INPUT を実行します。この処理の記述は次のようになります。
if (in_sqlda->sqld > in_sqlda->sqln)
{
n = in_sqlda->sqld;
第 13 章 動的 SQL
13-27
DSQL のプログラミング手法
free(in_sqlda);
in_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
in_sqlda->sqln = n;
in_sqlda->version = SQLDA_CURRENT_VERSION;
EXEC SQL
DESCRIBE INPUT SQL_STMT USING SQL DESCRIPTOR in_sqlda;
}
5
入力 XSQLDA 内の各 XSQLVAR パラメータ構造体を処理します。各パラメータ構造体の
処理は、次の 4 段階に分かれます。
• パラメータのデータ型を強制変換する(オプション)
。
• データ(XSQLVAR の sqldata フィールドによって示される)を格納するローカル領
域を確保する。この処理は、実行時にローカル変数の領域の割り当てが行われてい
ない場合に限り必要です。次に、ローカル変数の格納領域を動的に割り当てる例が
あるため、そちらを参考にしてください。
• パラメータに値を設定する。値は、パラメータに定義されているデータ型で設定し
なければなりません。この処理は必須です。
• パラメータ用の NULL 値インジケータを用意する。
これらの処理は、上記の順序で行わなければなりません。次のコードは、in_sqlda の中
の XSQLVAR 構造体(パラメータに対応)ごとにループして、これらの処理を行ってい
ます。
for (i=0, var = in_sqlda->sqlvar; i < in_sqlda->sqld; i++, var++)
{
/* ここで、XSQLVAR パラメータ構造体を処理する
パラメータ構造体は、var で示す */
dtype = (var->sqltype & ~1) /* ここで、フラグビットを削除します */
switch (dtype)
{
case SQL_VARYING:/* SQL_TEXT に強制変換します */
var->sqltype = SQL_TEXT;
/* 適切な格納領域を割り当てます */
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
/* パラメータに値を設定します。SQL_LONG のケースを参照 */
. . .
break;
case SQL_TEXT:
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
/* パラメータに値を設定します。SQL_LONG のケースを参照 */
. . .
break;
case SQL_LONG:
var->sqldata = (char *)malloc(sizeof(long));
/* パラメータに値を設定します */
*(long *)(var->sqldata) = 17;
13-28 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
break;
. . .
} /* switch 文の終わり */
if (sqltype & 1)
{
/* NULL ステータスを保持する変数を割り当てます */
var->sqlind = (short *)malloc(sizeof(short));
}
}
/* for ループの終わり */
データ型の強制変換と NULL インジケータについては、13-15 ページの「データ型の
強制変換」を参照してください。
6
DESCRIBE OUTPUT を使用して、SQL 文から返されるデータの情報を出力 XSQLDA に
渡します。
EXEC SQL
DESCRIBE OUTPUT SQL_STMT INTO SQL DESCRIPTOR out_sqlda;
7
XSQLDA の sqln フィールドの値と XSQLDA の sqld フィールドの値を比較し、クエリーで
返される選択リストを全部格納できるだけの数の XSQLVAR が割り当てられているかどう
かを検査します。ここで、sqln フィールドの値が sqld フィールドの値より小さいときは、
先に XSQLDA に割り当てた領域をいったん解放し、選択リストの数(sqld フィールドで
示されます)に見合うだけの領域を再度割り当てます。また、sqln と version を再設定し、
もう一度 DESCRIBE OUTPUT を実行します。この処理の記述は次のようになります。
if (out_sqlda->sqld > out_sqlda->sqln)
{
n = out_sqlda->sqld;
free(out_sqlda);
out_sqlda = (XSQLDA *)malloc(XSQLDA_LENGTH(n));
out_sqlda->sqln = n;
out_sqlda->version = SQLDA_CURRENT_VERSION;
EXEC SQL
DESCRIBE OUTPUT SQL_STMT INTO SQL DESCRIPTOR out_sqlda;
}
8
データを表す XSQLVAR 構造体をそれぞれ処理します。次の手順にしたがいます。
• データのデータ型を強制変換する(オプション)
。
• データ(XSQLVAR の sqldata フィールドによって示される)を格納するローカル領
域を確保する。この処理は、実行時にローカル変数の領域の割り当てが行われてい
ない場合に限り必要です。次に、ローカル変数の格納領域を動的に割り当てる例が
あるため、そちらを参考にしてください。
• データ用の NULL 値インジケータを用意します(オプション)
。
以上の処理を記述するコードは次のとおりです。ここでは、XSQLDA 構造体 out_sqlda
の中の各 XSQLVAR 構造体をループで処理しています。
for (i=0, var = out_sqlda->sqlvar; i < out_sqlda->sqld; i++, var++)
{
第 13 章 動的 SQL
13-29
DSQL のプログラミング手法
dtype = (var->sqltype & ~1) /* ここで、フラグビットを削除します */
switch (dtype)
{
case SQL_VARYING:
var->sqltype = SQL_TEXT;
break;
case SQL_TEXT:
var->sqldata = (char *)malloc(sizeof(char)*var->sqllen);
break;
case SQL_LONG:
var->sqldata = (char *)malloc(sizeof(long));
break;
/* 残りの型を処理します */
} /* switch 文の終わり */
if (sqltype & 1)
{
/* NULL ステータスを保持する変数を割り当てます */
var->sqlind = (short *)malloc(sizeof(short));
}
}
/* for ループの終わり */
データ型の強制変換と NULL インジケータについては、13-15 ページの「データ型の
強制変換」を参照してください。
クエリー SQL 文の文字列のカーソルによる実行
クエリー SQL 文の文字列の準備ができたら、カーソルを使って SQL 文を実行し選択リスト
を取り出します。なお、InterBase でのカーソル宣言はすべてコンパイルの時点で固定され
るとともに、埋め込んだ文もアプリケーションに挿入されます。したがって、DSQL アプリ
ケーションを作成する場合は、事前に使用されると思われるカーソルを想定し宣言してお
く必要があります。
カーソルを使って SQL 文を実行する場合は、ループ構造を使用します。この場合、まず 1 行
だけ取り出し、その行について選択リスト項目(列のデータ)を処理します。その後、同様
に次の行の取り出しと選択リストの処理を行います。
カーソルによる SQL 文の実行と行の取り出しと選択リスト項目の処理は、次の手順で行い
ます。
1
SQL 文の文字列の実行に必要なカーソルを宣言します。たとえば、次は、SQL_STMT と
いう名前の SQL 文の文字列で使用するカーソルとして DYN_CURSOR を宣言している
例です。
EXEC SQL
DECLARE DYN_CURSOR CURSOR FOR SQL_STMT;
2
宣言したカーソルを開きます。ここでは、入力 XSQLDA を指定します。
EXEC SQL
OPEN DYN_CURSOR USING SQL DESCRIPTOR in_sqlda;
13-30 埋 め 込 み S Q L ガ イ ド
DSQL のプログラミング手法
SQL 文の文字列は、カーソルを開くと同時に実行されるとともに、行のアクティブ
セットが作成されます。カーソルとアクティブセットの詳細は、第 6 章「データ処理」
を参照してください。
3
ループを使って行を 1 行ずつ取り出し、各行について選択リスト(列のデータ)を処理
します。たとえば、次は、DYN_CURSOR カーソルを使って行を 1 行ずつ取り出すとと
もに、各行について選択リスト項目の処理を行っているループの例です。ここでは、ア
プリケーション独自の関数(process_column())を使って行の列のデータを処理していま
す。
while (SQLCODE == 0)
{
EXEC SQL
FETCH DYN_CURSOR USING SQL DESCRIPTOR out_sqlda;
if (SQLCODE == 100)
break;
for (i = 0; i < out_sqlda->sqld; i++)
{
process_column(out_sqlda->sqlvar[i]);
}
}
4
全部の行の取り出しが完了したら、カーソルを閉じます。
EXEC SQL
CLOSE DYN_CURSOR;
パラメータを持つクエリー SQL 文の文字列の再実行
PREPARE を使ってパラメータを持つクエリー SQL 文の文字列の準備ができたら、
その SQL
文をアプリケーションで繰り返し使用することができます。この場合、プレースホルダ(入
力パラメータ)に新しいデータを入れるとともに NULL 値インジケータの設定を行います。
また、SQL 文から返されるデータの情報を出力 XSQLDA に渡します。さらに、カーソルを
閉じて、再度開く必要があります。
パラメータへの値の入力と NULL 値インジケータの設定は、この章の「パラメータを持つ
クエリー SQL 文の文字列の用意」の 3 から 5 までの手順を参照してください。
SQL 文によって返されるデータの情報を出力 XSQLDA に渡す処理は、この章の「パラメー
タを持つクエリー SQL 文の文字列の用意」の 6 から 8 までの手順を参照してください。
カーソルを再度開いて選択リスト項目を処理するには、この章の「クエリー SQL 文の文字
列のカーソルによる実行」のステップ 2 ~ 4 を繰り返してください。
第 13 章 動的 SQL
13-31
13-32 埋 め 込 み S Q L ガ イ ド
第
章
前処理、コンパイル、リンク
第 14 章
この章では、gpre を使ってプログラムを前処理する方法と、前処理したプログラムをコン
パイルおよびリンクして実行できるようにする方法について説明します。
gpre プリプロセッサは、サーバー ライセンスを購入すると付いてきます。これは C/C++
上でのみ動作保証されていますが、他の多くの言語でも動作します。
前処理
SQL プログラムまたは動的 SQL(DSQL)プログラムをコーディングしたら、そのプログラ
ムをコンパイルする前に gpre で前処理する必要があります。gpre では、InterBase ライブラ
リ関数呼び出しを生成することで、SQL コマンドや DSQL コマンドをホスト言語のコンパ
イラで処理できるステートメントに変換します。gpre では、SQL や DSQL のデータベース
変数をホスト言語のコンパイラで処理できる変数に変換し、それらの変数をホスト言語の
形式で宣言します。さらに、gpre では、SQLCODE 変数や DSQL で使用される拡張 SQL ディ
スクリプタ エリア(XSQLDA)など、SQL に必要な特定の変数やデータ構造も宣言します。
gpre の使用
gpre の構文は次のとおりです。
gpre [-language] [-options] infile [outfile]
infile 引数は入力ファイルの名前を指定します。
省略可能な outfile 引数は出力ファイルの名前を指定します。ファイルが指定されない場
合、gpre は入力ファイルと同じ名前のファイルに出力を送ります。この出力ファイルの拡
張子は入力ファイルの言語によって異なります。
第 14 章 前処理、コンパイル、リンク
14-1
前処理
gpre には、ソース プログラムの言語と他の多数のオプションを指定できるスイッチがあり
ます。これらのスイッチは、入出力ファイル指定の前か後に付けることができます。各ス
イッチには少なくとも、スペースの後にハイフンとそのスイッチを指定する一意な文字が
含まれている必要があります。
言語スイッチ
言語スイッチは、ソース プログラムの言語を指定するものです。C と C++ はすべてのプ
ラットフォームで使用可能な言語です。これらのスイッチを以下の表に示します。
表 14.1 すべてのプラットフォームで使用可能な gpre 言語スイッチ
スイッチ
言語
-c
C
-cxx
C++
さらに、他の言語をサポートしているプラットフォームもあります。ただし、その言語用
の追加 InterBase ライセンスを購入した場合に限ります。これらの使用可能な言語とそれに
対応するスイッチの一覧を以下の表に示します。
表 14.2 追加の gpre 言語スイッチ
スイッチ
言語
-al[sys]
Ada(Alsys 版)
-a[da]
Ada(VERDIX 版、VMS 版、TeleSoft 版)
-ansi
ANSI-85 COBOL
-co[bol]
COBOL
-f[ortran]
FORTRAN
-pa[scal]
Pascal
たとえば、census.e という C プログラムを前処理するには、次のように入力します。
gpre -c census.e
14-2 埋 め 込 み S Q L ガ イ ド
前処理
オプション スイッチ
オプション スイッチは、前処理オプションを指定するものです。使用可能なスイッチを以
下の表で説明します。
表 14.3 gpre オプション スイッチ
スイッチ
説明
-charset name
コンパイル時に使用されるキャラクタ セットを限定します。なお、
name はキャラクタ セット名です。
-d[atabase] filename
プログラムのデータベースを宣言します。filename はアクセスする
データベースのファイル名です。このオプションを使用するのは、
プログラムに SQL 文が含まれていて、そのプログラムがデータベー
スそのものに接続していない場合です。プログラムにデータベース
宣言が含まれている場合には、このオプションを使用しないでくだ
さい。
-d_float
VAX/VMS の場合のみ使用可能です。倍精度データが D_FLOAT 形
式でアプリケーションから渡され G_FLOAT 形式でデータベースに
格納されることを指定します。データベース内でのデータ比較は
G_FLOAT 形式で実行されます。データベースからアプリケーショ
ンに返されるデータは D_FLOAT 形式になります。
-e[ither_case]
gpre で大文字と小文字を両方とも認識できるようにします。コード
常に -either_case
内に SQL キーワードが小文字で現われる場合は、
スイッチを使用します。大文字と小文字が混在している場合、この
スイッチを使用しないと、gpre で入力ファイルを処理できません。
C 以外の言語では、大文字と小文字が区別されないため、このス
イッチは不要です。
-m[anual]
トランザクションを自動的に生成しないようにします。-m スイッ
チを使用するのは、独自のトランザクション処理を行う SQL プログ
ラムの場合と、本来独自のトランザクションを明示的に制御しなけ
ればならないすべての DSQL プログラムの場合です。
-n[o_lines]
C プログラムの場合に、行番号を出力に含めません。
-o[utput]
gpre の出力をファイルではなく標準出力に対して行います。
-password password
データベース パスワードの入力が必要なデータベースにプログラ
ムから接続する場合は、そのパスワード password を指定します。
-r[aw]
BLR を同等のニーモニックではなく生の数値として出力します。こ
のオプションは、gpre の出力ファイルを小さくするのに役立つ場
合がありますが、ファイルが読みにくくなります。
-sql_dialect
SQL ダイアレクトを設定します。有効な値は 1、2、3 のいずれかで
す。
第 14 章 前処理、コンパイル、リンク
14-3
前処理
表 14.3 gpre オプション スイッチ ( 続き )
スイッチ
説明
-user username
データベース ユーザー名の入力が必要なデータベースにプログラ
ムから接続する場合は、そのユーザー名 username を指定します。
-x handle
-database オプションで指定されたデータベース ハンドルの外部
宣言を有効にします。このオプションは、リンクされた別のモ
ジュールからグローバル宣言を取得するようにプログラムに指示
するものです。-d スイッチも併せて使用されている場合にのみ使
用します。
gpre のバージョン番号と宣言されているすべてのデータベースの
バージョン番号を出力します。これらのデータベースは、プログラ
ム内か -database スイッチで宣言することができます。
-z
適切なライセンスがあり C 以外の言語を使用しているサイトの場合は、以下の表に説明す
る追加の gpre オプションを指定することができます。
表 14.4 言語固有の gpre オプション スイッチ
スイッチ
説明
-h[andles] pkg
Ada ハンドル パッケージである pkg を指定します。
例
以下のコマンドでは、appl1.e というファイルの C プログラムを前処理しています。出力
ファイルは appl1.c になります。データベースが指定されていないため、ソース コードで
データベースに接続する必要があります。
gpre -c appl1
以下のコマンドは前のコマンドと同じですが、ソース コードでデータベースを開くと仮定
するのではなくデータベース mydb.ib を明示的に宣言している点が異なります。
gpre -c appl1 -d mydb.ib
gpre クライアント ダイアレクトの設定
デフォルトでは、gpre に接続先データベースのダイアレクトを指定できます。これにより、
gpre で以前のソース ファイルを変更せずに解析することができます。異なるダイアレクト
のクライアントとして動作するように gpre を設定することができます。それには以下のい
ずれかの方法を用います。
以下のように、オプション -sql_dialect n を付けて gpre を起動します(n は 1、2、3 の
いずれか)。
gpre -sql_dialect n
ソース コード内でダイアレクトを指定します。たとえば以下のように記述します。
EXEC SQL
SET SQL DIALECT n
14-4 埋 め 込 み S Q L ガ イ ド
前処理
gpre ダイアレクトの優先順位は以下のとおりです。
• 最低:接続しているデータベースのダイアレクト
• 中間:コマンド ラインで指定されたダイアレクト
• 最高:ソース コード内で指定されたダイアレクト
ファイル拡張子を用いた言語の指定
言語スイッチを用いてホスト言語を指定するだけでなく、ソース ファイルのファイル名拡
張子でホスト言語を指定することもできます。gpre でサポートしている言語ごとのファイ
ル名拡張子と出力ファイルのデフォルト拡張子を以下の表に示します。
表 14.5 ファイル拡張子による言語指定
言語
入力ファイル拡張子
デフォルトの出力ファイル拡張子
Ada(VERDIX 版)
ea
a
Ada(Alsys 版、TeleSoft 版) eada
ada
C
e
c
C++
exx
cxx
COBOL
ecob
cob
FORTRAN
ef
f
Pascal
epas
pas
たとえば、census.ecob という COBOL プログラムを前処理するには、次のように入力しま
す。
gpre census_report.ecob
これで、census.cob という出力ファイルが生成されます。
ファイル名拡張子を指定する際には、以下のように、言語スイッチを併せて指定すること
もできます。
gpre -cob census.ecob
ソース ファイルの指定
gpre のコマンドラインでは言語スイッチもファイル名拡張子も省略可能なため、以下の 3
とおりの状況が発生する可能性があります。
• 言語スイッチと拡張子なしの入力ファイルが指定されている
• 言語スイッチが指定されておらず拡張子付きの入力ファイルが指定されている
• 言語スイッチもファイル拡張子も指定されていない
このセクションでは、これらの各場合での gpre の動作について説明します。
第 14 章 前処理、コンパイル、リンク
14-5
前処理
言語スイッチと拡張子なしの入力ファイルが指定されている場合
gpre では、コマンドラインに言語スイッチが指定されているが指定された入力ファイルに
拡張子がない場合、以下のように動作します。
1
拡張子のない入力ファイルを探します。そのファイルが見つかった場合、gpre はそれ
を処理し、適切な拡張子の付いた出力ファイルを生成します。
該当する入力ファイルが見つからない場合、gpre は、指定された言語に対応する拡張
子の付いたファイルを探します。そのようなファイルが見つかった場合は、適切な拡張
子の付いた出力ファイルを生成します。
2
指定されたファイルも適切な拡張子の付いた指定ファイルも見つからなかった場合、
gpre は以下のエラーを返します。
gpre: can’t open filename or filename.extension
filename は gpre コマンドで指定されたファイルです。extension は指定されたプログ
ラムの言語固有のファイル拡張子です。
例
以下のコマンドが発行されたとしましょう。
gpre -c census
gpre は以下の一連のアクションを実行します。
1
拡張子の付いていない census というファイルを探します。そのファイルが見つかった
ら、それを処理して、census.c を生成します。
2 census
が見つからなかったら、census.e というファイルを探します。census.e が見つ
かったら、そのファイルを処理して、census.c を生成します。
3 census
も census.e も見つからなかったら、以下のエラーを返します。
gpre: can’t open census or census.e
言語スイッチが指定されておらず拡張子付きの入力ファイルが指定さ
れている場合
言語スイッチが指定されておらず拡張子付きの入力ファイルが指定されている場合、gpre
は指定されたファイルを探し、言語がその拡張子で指定されていると仮定します。
たとえば、以下のコマンドが処理されるとしましょう。
gpre census.e
gpre は census.e というファイルを探します。そのファイルが見つかった場合、gpre はそ
れを C プログラムとして処理し、census.c という出力ファイルを生成します。そのファイ
ルが見つからなかった場合、gpre は以下のエラーを返します。
gpre: can’t open census.e
14-6 埋 め 込 み S Q L ガ イ ド
コンパイルとリンク
言語スイッチもファイル拡張子も指定されていない場合
言語スイッチもファイル名拡張子も指定されていない場合、gpre は 以下の順序でファイル
を探します。
1
2
3
4
5
6
filename.e(C)
filename.epas(Pascal)
filename.ef(FORTRAN)
filename.ecob(COBOL)
filename.ea(VERDIX Ada)
filename.eada(Alsys 版および TeleSoft 版の Ada)
そのようなファイルが見つかった場合、gpre は適切な拡張子の付いた出力ファイルを生成
します。そのようなファイルが見つからなかった場合、gpre は以下のエラーを返します。
gpre: can’t find <filename> with any known extension. Giving up.
コンパイルとリンク
プログラムの前処理が終ったら、コンパイルとリンクを行う必要があります。コンパイル
すると、前処理されたソース ファイルからオブジェクト モジュールが生成されます。プロ
グラムをコンパイルするには、ホスト言語のコンパイラを使用します。リンク プロセスで
は、外部参照を解決し、実行可能オブジェクトを生成します。使用されるプラットフォー
ム、オペレーティング システム、ホスト言語に基づいてプログラムのオブジェクト モ
ジュールを他のオブジェクト モジュールやライブラリにリンクするには、指定されたプ
ラットフォームで使用可能なツールを使用します。
コードが埋め込み SQL プリプロセッサ gpre から生成された場合も、InterBase API を使っ
て作成された場合も、以下の手順が適用されます。アプリケーションは共有 GDS ライブラ
リのみとリンクします。
Microsoft Windows の場合
Windows では、アプリケーションのプロジェクトを作成するには、コマンドライン コンパ
イルではなく、できるだけ IDE を使用します。
C++ Builder
bcc32 -a4 -tWM -tWC -I<InterBase_home>\SDK\include application.c
-eapplication.exe <InterBase_home>\SDK\lib\gds32.lib
Microsoft Visual C++(C および C++)
cl -W3 -G4 -Gd -MD -I<InterBase_home>\SDK\include application.c
<InterBase_home>\SDK\lib\gds32_ms.lib /Feapplication.exe
第 14 章 前処理、コンパイル、リンク
14-7
コンパイルとリンク
Solaris の場合
SPARCWorks 4.2(C)
cc -mt -w -I/usr/InterBase/include -c application.c
cc -mt application.o -o application -lgdsmt
-lsocket -lthread -lsnl -ldl
SPARCWorks 4.2(C++)
CC -mt -w -I/usr/InterBase/include -c application.C
CC -mt application.o -o application -lgdsmt
-lsocket -lthread -lsnl -ldl
Ada プログラムのコンパイル
Ada プログラムをコンパイルする場合は、必ず、Ada ライブラリにパッケージ
InterBase.ada(VERDIX Ada の場合は InterBase.a)が含まれている必要があります。こ
のパッケージは InterBase の include ディレクトリにあります。
InterBase の examples ディレクトリにあるプログラムを使用する場合は、やはり examples
ディレクトリにあるパッケージ basic_io.ada(VERDIX Ada の場合は basic_io.a)を使用
してください。
UNIX 上でのリンク
Unix プラットフォームでは、プログラムを以下のライブラリとリンクすることができます。
• パイプを使用するライブラリ(-lgds オプションで取得)。このライブラリを利用すると、
リンクが速くなると共にイメージが小さくなります。さらに、InterBase の新しいバージョ
ンがインストールされたときにアプリケーションが自動的にそれと連動できるようになり
ます。
• パイプを使用しないライブラリ(-lgds_b オプションで取得)。このライブラリを利用する
と実行は速くなりますが、アプリケーションが InterBase の特定のバージョンでしか動作で
きなくなります。InterBase の新しいバージョンをインストールしたら、その新機能やその
バージョンで作成されたデータベースを使用できるようにプログラムをリンクし直す必要
があります。
SunOS-4 では、-lgdslib オプションを用いることで、プログラムを共有可能ライブラリと
リンクすることができます。それにより、実行時に動的リンクが生成され、イメージが小
さくなると共に完全なライブラリをリンクしたときの実行スピードが得られます。さらに、
このオプションを指定すると、InterBase バージョンを自動的にアップグレードできるよう
になります。
特定プラットフォームでの InterBase リンク オプションの詳細については、InterBase ディ
レクトリにあるオンライン readme を参照してください。
14-8 埋 め 込 み S Q L ガ イ ド
索引
記号
* 演算子 6-6
*(アスタリスク)6-20
+ 演算子 6-6
/ 演算子 6-6
[ ](ブラケット), 配列 9-2, 9-4 ~ 9-5
|| 演算子 6-6
– 演算子 6-6
A
Ada プログラム 14-8
ALIGN マクロ 13-16 ~ 13-17
ALL 演算子 6-8, 6-12
ALL キーワード 3-14
ALTER INDEX 5-18 ~ 5-19
ALTER TABLE 5-14 ~ 5-17
ADD オプション 5-15
DROP オプション 5-15
AND 演算子 6-7
ANY 演算子 6-8, 6-13
ASC キーワード 6-29
B
BASED ON 2-3 ~ 2-4
配列 9-5
basic_io.a 14-8
basic_io.ada 14-8
BEGIN DECLARE SECTION 2-3
BETWEEN 演算子 6-8
NOT 演算子 6-8
Binary Large Objects →「BLOB」
BLOB API 関数 8-11
BLOB サブタイプ 8-2
BLOB セグメント 8-3 ~ 8-5
BLOB データ 8-5 ~ 8-21
格納 8-2, 8-3
更新 8-9 ~ 8-10
削除 8-10
選択 8-6 ~ 8-8
挿入 8-8 ~ 8-9
フィルタリング 8-11 ~ 8-21
BLOB データ型
処理 6-3
Blob データに関する API 呼び出し 8-11
BLOB フィルタ 8-11 ~ 8-21
外部 8-12
書き込み 8-14
宣言 8-12
種類 8-14
テキスト 8-12
呼び出し 8-13
BLOB データ型
説明 6-2
Boolean 式 6-27
評価 6-7
Borland C/C++ →「C 言語」
C
C language
host-language variables 2-5
CACHE キーワード 3-13
CAST() 6-17, 7-6
CHAR VARYING キーワード 6-3
CHAR データ型
DATE への変換 7-6
CHARACTER VARYING キーワード 6-3
CHARACTER キーワード 6-2
CHAR データ型
説明 6-2
COLLATE 句 6-27
COMMIT 2-8, 3-16, 4-1, 4-21 ~ 4-25
複数のデータベース 3-4
COMPILETIME キーワード 3-4
CONNECT 2-6, 3-1, 3-6 ~ 3-14
ALL オプション 3-14
CACHE オプション 3-13
SET DATABASE 3-7
エラー処理 3-12
省略 2-6
複数のデータベース 3-8 ~ 3-12
CONTAINING 演算子 6-9
NOT 演算子 6-9
CREATE DATABASE 5-3 ~ 5-4
DSQL 内 13-4
キャラクタセットの指定 5-4
CREATE DOMAIN 5-4 ~ 5-5
配列 9-1
索引
I-1
CREATE GENERATOR 5-11 ~ 5-12
CREATE INDEX 5-10 ~ 5-11
DESCENDING オプション 5-11
UNIQUE オプション 5-11
CREATE PROCEDURE 10-2
CREATE TABLE 5-5 ~ 5-8
配列 9-1
マルチテーブル 5-6
CREATE VIEW 5-8 ~ 5-10
WITH CHECK OPTION 5-10
CURRENT_DATE 7-2
CURRENT_TIME 7-2
CURRENT_TIMESTAMP 7-2
D
DATE データ型
説明 7-1
変換 7-6, 7-7
DATE 日付リテラル 7-9
DATE データ型
説明 6-2
DECIMAL データ型 6-2
DECLARE CURSOR 4-27
DECLARE TABLE 5-7
DESC キーワード 6-29
DESCENDING キーワード 5-11
DISCONNECT 2-9, 3-15
複数のデータベース 3-4, 3-15
DISTINCT キーワード 6-21
DOUBLE PRECISION データ型 6-2
DROP INDEX 5-12
DROP TABLE 5-13
DROP VIEW 5-13
DSQL
CREATE DATABASE 13-4
制限 13-1
必要条件 2-9 ~ 2-10
プログラミング手法 13-17 ~ 13-31
マクロ定数 13-12 ~ 13-14
DSQL アプリケーション 2-1, 13-1
SQL 文、埋め込み 2-12
XSQLDA 13-7 ~ 13-17
移植 2-2
書き込み 13-5
実行可能プロシージャ 10-5
データ型 13-14 ~ 13-17
データ定義文 5-1
I-2
埋め込み SQL ガイド
データベースの作成 13-4
データベースハンドル 2-9, 2-11
データベースへの接続 13-2
データへのアクセス 2-5, 2-12
デフォルトトランザクション 4-4
トランザクション 2-11
トランザクション名 2-9, 2-11 ~ 2-12
配列 9-3
必要条件 2-9 ~ 2-12
複数のトランザクション 4-29
前処理 2-13, 4-3
DSQL に関する制限事項 2-11 ~ 2-12
DSQL 文 13-1
DSQL アプリケーション
前処理 14-1
E
END DECLARE SECTION 2-3
ESCAPE 文字 6-11
EVENT INIT 11-3
複数のイベント 11-4
EVENT WAIT 11-4 ~ 11-5
EXECUTE 2-9, 2-12
EXECUTE IMMEDIATE 2-10, 2-12, 4-30
EXECUTE PROCEDURE 10-5
EXISTS 演算子 6-8, 6-13
NOT 演算子 6-13
EXTERN キーワード 3-5 ~ 3-6
EXTRACT() 7-2
F
FLOAT データ型 6-2
FOR UPDATE
SELECT 文 6-20
FROM
SELECT 文 6-19
FROM キーワード 6-24 ~ 6-26
G
GEN_ID() 5-12
gpre 2-13, 4-30, 14-1 ~ 14-7
DSQL アプリケーション 4-3
-m スイッチ 4-3, 5-2
クライアント ダイアレクト、指定 14-4
言語オプション 14-2
ファイル名拡張子 14-5 ~ 14-7
構文 14-1
コマンドライン オプション 14-3 ~ 14-4
ソース ファイルの指定 14-5
データベース 3-4
トランザクションの前処理 13-3
必要条件 2-1
古い -sqlda スイッチ 2-10
GROUP BY
SELECT 文 6-19
H
HAVING
SELECT 文 6-19
HAVING キーワード 6-31
isc_encode_date() 7-6
isc_encode_sql_date() 7-1
isc_encode_sql_time() 7-1
isc_encode_timestamp() 7-1
isc_get_segment() 8-11
isc_interprete() 12-9, 12-10 ~ 12-11
isc_open_blob2() 8-11
isc_put_segment() 8-11
ISC_QUAD 構造体 7-3 ~ 7-6
isc_sql_interprete() 12-9 ~ 12-10
isc_status 12-8, 12-12
ISC_TIMESTAMP 7-3
J
I
JOIN キーワード 6-34
I/O →「入力」「出力」
ibase.h 2-10, 12-12
IN 演算子 6-9
NOT 演算子 6-10
INDEX キーワード 6-34
INDICATOR キーワード 10-5
INSERT 6-18
statement 6-4
配列 9-4
INTEGER データ型 6-2
interbase.a 14-8
interbase.ada 14-8
INTO
SELECT 文 6-19
INTO キーワード 6-23, 6-35
IS NULL 演算子 6-11
NOT 演算子 6-11
isc_$event 11-5
isc_blob_ctl 8-16
フィールドの説明 8-17
isc_blob_default_desc() 8-11
isc_blob_gen_bpb() 8-11
isc_blob_info() 8-11
isc_blob_lookup_desc() 8-11
isc_blob_set_desc() 8-11
isc_cancel_blob() 8-11
isc_close_blob() 8-11
isc_create_blob2() 8-11
isc_decode_date() 7-3
isc_decode_sql_date() 7-1
isc_decode_sql_time() 7-1
isc_decode_timestamp() 7-1
L
LIKE 演算子 6-10
NOT 演算子 6-11
limbo トランザクション 2-8
M
-m スイッチ 4-3
Microsoft C/C++ →「C 言語」
N
NATURAL キーワード 6-34
NO RECORD_VERSION 4-8
NO WAIT 4-8, 4-16
NONE キャラクタセットオプション 5-4
NOT 演算子 6-7
BETWEEN 演算子 6-8
CONTAINING 演算子 6-9
EXISTS 演算子 6-13
IN 演算子 6-10
IS NULL 演算子 6-11
LIKE 演算子 6-11
SINGULAR 演算子 6-14
STARTING WITH 演算子 6-12
NOW 6-5
NULL 値
インジケータ変数 10-5
集計関数 6-22
配列 9-3
比較 6-8, 6-13
NUMERIC データ型
索引
I-3
DATE への変換 7-6
6-3
O
OR 演算子 6-7
ORDER BY
SELECT 文 6-20
ORDER キーワード 6-34
P
PLAN
SELECT 文 6-19
PLAN キーワード 6-34
POST_EVENT 11-2
PREPARE 2-9, 4-30
PRIMARY KEY 制約 5-11
PROTECTED READ 4-18
PROTECTED WRITE 4-18
R
READ COMMITTED 4-8, 4-10, 4-12
RECORD_VERSION 4-8
RESERVING 句 4-8, 4-17
テーブル予約 4-18
ROLLBACK 2-8, 3-16, 4-1, 4-21, 4-25 ~ 4-26
複数のデータベース 3-4
RUNTIME キーワード 3-4
S
SELECT 6-4 ~ 6-14, 6-18 ~ 6-35, 10-3
CREATE VIEW 5-8, 5-9
DISTINCT オプション 6-21
FROM 句 6-24 ~ 6-26
GROUP BY 句 6-30 ~ 6-31
照合順序 6-31
HAVING 句 6-31
INTO 句 6-23, 6-35
ORDER BY 句 6-29
照合順序 6-30
PLAN 句 6-34
SELECT 文 6-19
TRANSACTION 句 6-23
WHERE 句 6-4 ~ 6-17, 6-26 ~ 6-28, 6-35
ALL 演算子 6-12
ANY 演算子 6-13
BETWEEN 演算子 6-8
I-4
埋め込み SQL ガイド
CAST オプション 6-17, 7-6
CONTAINING 演算子 6-9
EXISTS 演算子 6-13
IN 演算子 6-9
IS NULL 演算子 6-11
LIKE 演算子 6-10
SINGULAR 演算子 6-14
SOME 演算子 6-13
STARTING WITH 演算子 6-12
照合順序 6-28
句の一覧 6-19
配列 9-4 ~ 9-6
SELECT 文
単一行 SELECT 6-18, 6-23, 6-35
サブクエリーとして使用 6-5
SET DATABASE 2-5 ~ 2-6, 3-1
COMPILETIME オプション 3-4
CONNECT 3-7
DSQL アプリケーション 2-11
EXTERN オプション 3-5 ~ 3-6
RUNTIME オプション 3-4
STATIC オプション 3-5 ~ 3-6
省略 2-6, 3-9
マルチデータベース 3-3, 3-10
SET NAMES 3-1
SET TRANSACTION 4-1, 4-3, 4-7 ~ 4-19
アクセスモードパラメータ 4-1
構文 4-9
パラメータ 4-8
SHARED READ 4-18
SHARED WRITE 4-18
SINGULAR 演算子 6-8, 6-14
NOT 演算子 6-14
SMALLINT データ型 6-3
SNAPSHOT 4-8, 4-10, 4-12
SNAPSHOT TABLE STABILITY 4-8, 4-10, 415
SOME 演算子 6-8, 6-13
SORT MERGE キーワード 6-34
SQL 文
DSQL アプリケーション 2-12
ターミネータ 2-7
ホスト言語変数 2-2
文字変数 2-3
文字列 13-6
SQLCODE 変数
検査 12-4, 12-6
検証 12-1
宣言 2-7
戻り値 12-1, 12-8, 12-12
表示 12-8
SQLDA 2-10
アプリケーションの移植 2-2
SQL ダイアレクト 14-4
STARTING WITH 演算子 6-12
NOT 演算子 6-12
STATIC キーワード 3-5 ~ 3-6
SunOS-4 プラットフォーム 14-8
T
TIME データ型
変換 7-6, 7-7
time.h 7-3
TIMESTAMP データ型
変換 7-6, 7-7
6-3
TIME データ型 6-3
TODAY 6-5
TODAY 日付リテラル 7-9
TOMORROW 6-5
TRANSACTION キーワード 6-23
U
UDF
配列 9-3
UNION
SELECT 文 6-19
テーブルの付加 6-33
UNIQUE キーワード 5-11
Unix プラットフォーム 14-8
UPDATE
statement 6-4
データ 6-60
配列 9-7
日付 7-6
UPPER() 6-17
USING 句 4-8, 4-18
V
VARCHAR データ型 6-3
W
WAIT 4-8, 4-16
WHENEVER 12-2 ~ 12-4, 12-6
埋め込み 12-3
スコープ 12-3
制限 12-4
WHERE
SELECT 文 6-19
WHERE キーワード 6-26
WHERE 句
UPDATE 文の… 6-61
WHERE 句 →「SELECT」
X
XSQLDA 13-7 ~ 13-17
アプリケーションの移植 2-2
構造体 2-10
出力デスクリプタ 13-11
ストアドプロシージャ 10-6
宣言 2-10
入力デスクリプタ 13-11
フィールド 13-9
XSQLDA_LENGTH マクロ 13-11
XSQLVAR 構造体 13-7
フィールド 13-9
Y
YESTERDAY 6-5
あ
アクション →「イベント」
アクセス
BLOB データ 8-11
データ 2-5, 3-11, 3-14
配列 9-3 ~ 9-8
アクセス特権 →「セキュリティ」
アクセスモードパラメータ 4-9
デフォルトトランザクション 4-3
アスタリスク(*)6-20
値
一意 5-11
最小 6-21
最大 6-21
ストアドプロシージャ 10-2, 10-6
選択 6-21
操作 6-6
比較 6-7
マッチング 6-9, 6-13
…が存在しない行の検査 6-11
索引
I-5
⇒「NULL 値」
アプリケーション 2-1
移植 2-2, 12-7
イベントハンドリング 11-1, 11-3 ~ 11-5
作成 5-4
前処理 →「gpre」
⇒「DSQL アプリケーション」
アラータ(イベント)11-2
い
移植
アプリケーション 2-2, 12-7
配列 9-2
一意なインデックス 5-11
イベント 11-1 ~ 11-5
アラータ 11-2
応答 11-5
通知 11-2, 11-3 ~ 11-4
定義 11-1
複数 11-4 ~ 11-5
マネージャ 11-1
⇒「トリガー」
インジケータ変数 10-5
NULL 値 10-5
インデックス
一意 5-11
削除 5-12
作成 5-10 ~ 5-11
システム定義 5-11
重複する値の排除 5-11
主キー 5-11
ソート順序 5-11
キャッシュ 5-19
変更 5-14, 5-18 ~ 5-19
え
エイリアス
データベース 3-2
テーブル 6-25
エラー 2-7
実行時…
…からの復旧 12-1
トラップ 12-2, 12-4, 12-12
ユーザー定義 →「例外」
予期しない 12-7
エラーコードとメッセージ 2-7, 12-12
取り込み 12-9 ~ 12-11
I-6
埋め込み SQL ガイド
表示 12-8
エラー処理ルーチン 3-12, 12-1, 12-7
SQLCODE の直接検査 12-4, 12-6
WHENEVER 12-2 ~ 12-4, 12-6
ガイドライン 12-7
キャッシュ 12-3
ネスト 12-7
無効にする 12-7
エラーステータス配列 12-8, 12-12
演算子
算術 6-6
比較 6-7 ~ 6-14
文字列 6-6
優先順位 6-14 ~ 6-17
キャッシュ 6-16
連結 6-6
論理 6-7
演算子の評価順 6-14 ~ 6-17
キャッシュ 6-16
演算子の優先順位 6-14 ~ 6-17
キャッシュ 6-16
お
大文字と小文字の区別 6-9, 6-10, 6-12
オブジェクト モジュール 14-7
か
カーソル 6-36
選択プロシージャ 10-4
配列 9-4, 9-6
マルチトランザクションプログラム 4-27
外部 BLOB フィルタの作成方法 8-14
拡張 SQL デスクリプタエリア →「XSQLDA」
加算(+)6-6
仮想テーブル 5-8
関数
エラー処理 12-7
集合 6-21 ~ 6-22
数値 5-12
変換 6-17 ~ 6-18, 7-6
ユーザー定義 →「UDF」
き
キー
一次… 5-11
キー制約 →「FOREIGN KEY 制約」
「PRIMARY KEY 制約」
起動 , デフォルトトランザクション 4-2 ~ 4-4
キャッシュバッファ 3-13 ~ 3-14
キャラクタセット
NONE 5-4
指定 3-6, 5-4
デフォルト 5-4
変換 6-12
行
グループ化 6-30
制限 6-31
計算 6-21
選択 6-26
単一 6-35
複数 6-24, 6-35 ~ 6-43
ソート 6-29
行が基準の配列順 9-2
行のグループ化 6-30
制限 6-31
く
クエリー 5-10, 6-18
行のグループ化 6-30
行の絞り込み 6-26, 6-31
結合の使用 6-25, 6-34
検索条件 6-4 ~ 6-14, 6-26 ~ 6-28
2 つの簡単な条件 6-7
逆転 6-7
配列 9-8
指定テーブル 6-24 ~ 6-26
重複した列の排除 6-21
ソート 6-29
単一行の選択 6-35
複数行の選択 6-24, 6-35 ~ 6-43
マルチカラムのソート 6-29
⇒「SQL」
クエリー最適化機能 6-34
区切り付き識別子 5-3
グループ集合 6-30
グローバルな列定義 5-4
け
計算列
作成 5-7, 5-15
定義 5-7
結果テーブル 6-35
⇒「結合」
結合 6-25
言語オプション(gpre)14-2
ファイル名拡張子 14-5 ~ 14-7
検索条件(クエリー)6-4 ~ 6-14, 6-26 ~ 6-28
2 つの簡単な条件 6-7
逆転 6-7
配列 9-8
減算(-)6-6
こ
合計値 6-21
降順ソート 5-11, 6-29
更新
⇒「変更」
更新 , BLOB データ 8-9 ~ 8-10
更新可能ビュー 5-9
更新喪失 4-11
更新副作用 4-11
国際キャラクタセット 6-12
コンパイル
プログラム 14-7 ~ 14-8
さ
再現不能読み取り 4-11
最小値 6-21
最大値 6-21
最適化
データの取得 6-34, 10-1
削除
メタデータ 5-12 ~ 5-13
列 5-15
削除 →「削除」
作成
計算列 5-7, 5-15
整合性制約 5-5
配列 9-1 ~ 9-3
メタデータ 5-2 ~ 5-12
列 5-5
サブクエリー
定義 6-51
比較演算子 6-8, 6-10 ~ 6-14
算術 6-6, 6-21
算術演算子 6-6
優先順位 6-6, 6-15
算術関数 →「集計関数」
算術式 9-8
索引
I-7
し
ジェネレータ
作成 5-11 ~ 5-12
定義 5-11
式 6-27
評価 6-7
式ベースの列 →「計算列」
識別 3-2
データベース 3-7
データベースハンドル 3-2
ビュー 5-8
時刻
更新 7-6
挿入 7-5
テーブルから取り出す 7-1
変換 7-11
時刻構造体 7-3
システム定義のインデックス 5-11
システムテーブル 5-3
実行可能オブジェクト 14-7
実行可能プロシージャ 10-2, 10-4 ~ 10-6
DSQL 10-5
入力パラメータ 10-5 ~ 10-6
実行時エラー
…からの復旧 12-1
指定
キャラクタセット 3-6, 5-4
ディレクトリ 3-2
ファイル名 3-8 ~ 3-9
ホスト 3-2
ホスト言語変数 6-23
射影 6-18
集計関数 6-21 ~ 6-22
NULL 値 6-22
配列 9-3
修正 ⇒「変更」「更新」
主キー 5-11
出力パラメータ
⇒「ストアドプロシージャ」
照合順序
GROUP BY 句 6-31
ORDER BY 句 6-30
WHERE 句 6-28
乗算(*)6-6
昇順ソート 5-11, 6-29
初期化
データベース 2-5 ~ 2-7
I-8
埋め込み SQL ガイド
トランザクション名 4-6
除算(/)6-6
す
数値
作成 5-11
数値 →「値」
数値関数 5-12
スコープ
WHENEVER 12-3
キャッシュ 3-5
データベースハンドル 3-5
スコープの調整 3-5
スティッキーソート順 6-29
ステータス配列 →「エラーステータス配列」
ステートメント
トランザクション操作 4-1, 4-2
⇒「DSQL 文」「SQL 文」
ストアドプロシージャ 10-1 ~ 10-6, 11-1
XSQLDA 10-6
値 10-2, 10-6
定義 10-1
戻り値 10-2, 10-6
せ
整合性制約 5-5
オプション 5-6
→ 各制約名も参照
制約 5-5, 5-12, 5-13, 5-14, 5-15
オプション 5-6
→「特定 , 定義」
宣言
1 つのデータベースのみ 2-6, 3-1
BLOB フィルタ 8-12
SQLCODE 変数 2-7
XSQLDA 2-10
トランザクション名 4-6
複数のデータベース 2-5 ~ 2-6, 3-2 ~ 3-5
ホスト言語変数 2-2 ~ 2-5
選択
BLOB データ 8-6 ~ 8-8
単一行 6-35
データ 5-10, 6-4, 6-18
⇒「SELECT」
日付 7-3
ビュー 6-24
複数行 6-24, 6-35 ~ 6-43
列 6-20 ~ 6-23
選択プロシージャ 10-2, 10-3 ~ 10-4
カーソル 10-4
選択 6-24
テーブル 10-3
入力パラメータ 10-3
ビュー 10-3
呼び出し 10-4
全部のデータベースハンドル 3-5
そ
挿入
BLOB データ 8-8 ~ 8-9
日付 7-5 ~ 7-6
→「追加」
添字(配列)9-2 ~ 9-3, 9-8
ソース ファイル 14-5
ソート
行 6-29
マルチカラム 6-29
ソート順序
インデックス 5-11, 5-19
クエリー 6-29
降順 5-11, 6-29
昇順 5-11, 6-29
スティッキー 6-29
存在しない , 値が…行の検査 6-11
た
ダーティ読み取り 4-11
ダイアレクト 14-4
ダイナミックリンクライブラリ →「DLL」
対話型 SQL →「isql」
多次元配列
作成 9-2
データの選択 9-6
単一行 SELECT 6-18, 6-23
定義 6-35
つ
追加
列 5-15
⇒「挿入」
て
ディレクトリ
指定 3-2
データ 6-1
アクセス 2-5, 3-11, 3-14
DSQL アプリケーション 2-5, 2-12
ホスト変数 2-2
格納 9-1
取得
最適化 6-34, 10-1
選択 5-10, 6-4, 6-18
マルチテーブル 6-22, 6-24
定義 5-1
変更
コミット →「COMMIT」
ロールバック →「ROLLBACK」
保護 →「セキュリティ」
データ型 6-2, 6-3
DSQL アプリケーション 13-14 ~ 13-17
強制変換 13-15 ~ 13-16
互換性 6-17
変換 6-17
マクロ定数 13-12 ~ 13-14
データ型の強制変換 13-15 ~ 13-16
データ構造体
ホスト言語 2-4
データの保護 →「セキュリティ」
データベース
DSQL で接続 13-2
作成 5-3 ~ 5-4
初期化 2-5 ~ 2-7
接続 2-6, 3-6
複数 3-3, 3-8, 3-11
閉じる 2-9, 3-4, 3-15 ~ 3-16
名前 3-7
開く 3-1, 3-6, 3-8
複数の宣言 2-5 ~ 2-6, 3-2 ~ 3-5
リモート 5-3
データベースキャッシュバッファ 3-13 ~ 3-14
データベース指定 4-1, 4-8
データベースの接続解除 3-4, 3-15
データベースハンドル 2-5, 3-2, 3-7
DSQL アプリケーション 2-9, 2-11
global 3-5
スコープ 3-5
トランザクション 3-2, 3-14
名前 3-2
複数のデータベース 3-2 ~ 3-4, 3-10
データベースへの接続 2-6, 3-6
複数 3-3, 3-8 ~ 3-11
テーブル
索引
I-9
UNION による…の付加 6-33
クエリー指定 6-24 ~ 6-26
削除 5-13
作成 5-5 ~ 5-8
複数 5-6
識別 3-2, 3-3, 3-14
宣言 5-7
選択プロシージャ 10-3
変更 5-14 ~ 5-17
テーブルの付加 6-33
テーブル名
エイリアス 6-25
識別 3-2, 3-3, 3-14
複製 5-6
テーブル予約 4-1, 4-8
デフォルトキャラクタセット 5-4
デフォルトトランザクション
DSQL アプリケーション 4-4
アクセスモードパラメータ 4-3
起動 4-2 ~ 4-4
デフォルトの動作 4-3
排他レベルパラメータ 4-3
ロールバック 2-8
ロック対応パラメータ 4-3
と
動的 SQL →「DSQL」
特定(定義)3-2, 3-14
閉じる
データベース 2-9, 3-4, 3-15 ~ 3-16
複数 3-4
トランザクション 2-8
特権 →「セキュリティ」
ドメイン
作成 5-4 ~ 5-5
トラップ
エラー 12-2, 12-4, 12-12
トランザクション 10-2
DSQL アプリケーション 2-11
コミット 2-8
終了 4-21
データベースハンドル 3-2, 3-14
データへのアクセス 3-14
デフォルト 4-2 ~ 4-4
ロールバック 2-8
閉じる 2-7 ~ 2-8
名前 4-5 ~ 4-7
I-10 埋 め 込 み S Q L ガ イ ド
名前がない… 2-8
名前付き 4-2, 4-19
起動 4-4 ~ 4-5
複数のデータベース 3-14
複数の…の実行 4-26 ~ 4-31, 6-22
ロールバック 2-8
トランザクション操作文 4-1, 4-2
トランザクション名 4-4, 13-3
DSQL アプリケーション 2-9, 2-11 ~ 2-12
初期化 4-6
宣言 4-6
マルチテーブル 6-22
トリガー 11-1
な
名前
識別 3-2, 3-3, 3-14
SELECT 文 6-22
実行時に指定 3-8
データベース 3-7
データベースハンドル 3-2
トランザクション 4-5 ~ 4-7
ビュー 5-8
メタデータ名の長さ 5-2
列 5-8, 6-22
名前付きトランザクション 4-2, 4-19
起動 4-4 ~ 4-5
に
入力パラメータ 10-3, 10-5 ~ 10-6
⇒「ストアドプロシージャ」
は
ハードコードされた文字列
ファイル名 3-8 ~ 3-9
排他レベルパラメータ 4-1, 4-8, 4-10
デフォルトトランザクション 4-3
バイト一致規則 6-12
配列 6-3
DSQL アプリケーション 9-3
UDF 9-3
アクセス 9-3 ~ 9-8
カーソル 9-4, 9-6
格納 , データ 9-1
検索条件 9-8
更新 9-6
作成 9-1 ~ 9-3
参照 9-3
集計関数 9-3
添字 9-2 ~ 9-3, 9-8
多次元… 9-2, 9-6
データの選択 9-4 ~ 9-6
データの挿入 9-4
ビュー 9-3
⇒「エラーステータス配列」
配列 ID 9-4
配列スライス 9-5 ~ 9-6
定義 9-3
データ挿入 9-3
データの更新 9-6
配列要素 9-5
移植 9-2
取得 9-5
定義 9-1
評価 9-8
バッファ
データベースキャッシュ 3-13 ~ 3-14
パラメータ
アクセスモード 4-3, 4-9
データベース指定 4-1, 4-8, 4-18
テーブル予約 4-1, 4-8, 4-18
排他レベル 4-1, 4-3, 4-8, 4-10
不明 10-5
ロック対応 4-1, 4-3, 4-8, 4-16
ひ
比較演算子 6-7 ~ 6-14
NULL 値 6-8, 6-13
サブクエリー 6-8, 6-10 ~ 6-14
優先順位 6-16
日付
書式化 7-4
更新 7-6
選択 7-3
挿入 7-5 ~ 7-6
テーブルから取り出す 7-1
変換 7-1 ~ 7-10, 7-11
日付リテラル 6-5, 7-9
ビュー 5-8
更新可能 5-9
削除 5-13
作成 5-8 ~ 5-10
選択 6-24
選択プロシージャ 10-3
名前 5-8
配列 9-3
変更 5-14, 5-17
読み取り専用 5-9
列の定義 5-8
開く
データベース 3-1, 3-6, 3-8
複数 3-8
ふ
ファイル
ソース、指定 14-5
→ 各ファイル名も参照
ファイル名 , 指定 3-8 ~ 3-9
ファントム行 4-11
フィルタ関数 8-14
動作マクロの定義 8-18 ~ 8-20
戻り値 8-20 ~ 8-21
複数行の選択 6-24, 6-35 ~ 6-43
複数のデータベース
接続 3-3, 3-8, 3-11
接続解除 3-4, 3-15
宣言 2-5 ~ 2-6, 3-2 ~ 3-5
データベースハンドル 3-2 ~ 3-4, 3-10
閉じる 3-4
トランザクション 3-14
開く 3-8
複数のトランザクション 6-22
DSQL アプリケーション 4-29
実行 4-26 ~ 4-31
復旧不能なエラー 12-7
ブラケット([ ]), 配列 9-2, 9-4 ~ 9-5
プリプロセッサ →「gpre」
プログラミング
DSQL アプリケーション 2-9 ~ 2-12
gpre 2-1
プログラム、コンパイルとリンク 14-7 ~ 14-8
プロシージャ →「ストアドプロシージャ」
文
埋め込み 2-7, 6-1
エラー処理 12-7
データ構造体 2-4
データ定義 5-1
へ
平均 6-21
ヘッダーファイル →「ibase.h」
索引
I-11
変換
国際キャラクタセット 6-12
データ型 6-17
日付 7-1 ~ 7-10
日付と時刻のデータ型 7-7
変換関数 6-17 ~ 6-18, 7-6
変更
ビュー 5-14, 5-17
メタデータ 5-14 ~ 5-19
列定義 5-16
変数
インジケータ 10-5
ホスト言語 3-8
指定 6-23
宣言 2-2 ~ 2-5
配列 9-8
ほ
ホスト 3-2
ホスト言語 2-7
データ構造体 2-4
ホスト言語変数 3-8
指定 6-23
宣言 2-2 ~ 2-5
配列 9-8
ま
マクロ定数 13-12 ~ 13-14
マルチカラムのソート 6-29
マルチテーブル
作成 5-6
データの選択 6-22, 6-24
マルチモジュールプログラム 3-5
め
メタデータ 5-1
削除 5-12 ~ 5-13
失敗 5-14
作成 5-2 ~ 5-12
名前の長さ 5-2
変更 5-14 ~ 5-19
メモリ
割り当て 3-13
も
モジュール
オブジェクト 14-7
I-12 埋 め 込 み S Q L ガ イ ド
文字列
比較 6-9, 6-10, 6-12
リテラルファイル名 3-8 ~ 3-9
文字列演算子(||)6-6
ゆ
有効なデータベース 2-12
ユーザー定義関数 ⇒「UDF」
ユニーク値 5-11
よ
予期しないエラー 12-7
読み取り専用ビュー 5-9
ら
ライブラリ
Unix プラットフォーム 14-8
ダイナミックリンク →「DLL」
り
リテラルシンボル 6-11
リテラル文字列 , ファイル名 3-8 ~ 3-9
リモートデータベース 5-3
リンク
プログラム 14-7 ~ 14-8
る
ルーチン 10-2
⇒「エラー処理ルーチン」
ループ →「繰り返し文」
れ
列
返される値 6-21
計算型 5-7, 5-15
削除 5-15
作成 5-5
選択 6-20 ~ 6-23
重複データの排除 6-21
ソート順 6-29
追加 5-15
定義
ビュー 5-8
ドメインの使用 5-4
変更 5-16
列が基準の配列順 9-2
列名
識別 6-22
ビュー 5-8
連結演算子(||)6-6
ろ
ロールバック 2-8
ロック対応パラメータ 4-1, 4-8, 4-16
デフォルトトランザクション 4-3
論理演算子 6-7
優先順位 6-7, 6-16
わ
ワイルドカード , 文字列比較 6-10
割り当て , メモリ 3-13
索引
I-13