4.8.2 配列を使用したINSERT機能
(1) 概要
複数行分のデータを設定した配列型の変数を指定することで,一つのSQL文で複数行分のデータを挿入できます。配列を使用したINSERT機能を使用すると,HiRDBクライアントとHiRDBサーバとの間の通信回数を削減できます。また,HiRDB/パラレルサーバの場合には,更にHiRDBサーバ内のサーバ間の通信回数も削減できます。そのため,HiRDBクライアントからHiRDBサーバにアクセスし,大量のデータを高速に挿入したい場合に有効となります。
(2) 使用方法
(a) 静的に実行する場合
INSERT文でFOR句に埋込み変数を指定し,かつ指定する埋込み変数と標識変数をすべて配列型の変数にしてください。一括して挿入する行数は,FOR句に指定した埋込み変数で制御します。
(b) 動的に実行する場合
次に示す手順で実行してください。
-
PREPARE文で,INSERT文(一つ以上の?パラメタを指定)を前処理します。
-
EXECUTE文のUSING句に,前処理したINSERT文の入力?パラメタに与える値を配列で指定し,かつBY句に埋込み変数を指定してください。一括して挿入する行数は,BY句に指定した埋込み変数で制御します。
USING句で埋込み変数を指定する場合は,埋込み変数及び標識変数をすべて配列型の変数にしてください。
USING句でSQL記述領域を指定する場合は,SQLDATAが指すすべての領域に,データを配列形式で指定してください。また,SQLSYS領域にデータ型に応じた値を設定してください。
(3) 注意事項
INSERT文のFOR句,又はEXECUTE文のBY句の埋込み変数に,書き込み領域以上の行数を指定すると,DB破壊,又はUAP側の領域破壊となるおそれがあります。
(4) 使用例
配列を使用したINSERT機能のコーディング例について説明します。
- 例1:
-
INSERT文形式3を使用して,ファイルから読み出したデータを配列形式の埋込み変数に設定し,在庫表(ZAIKO)へ一括して50行分ずつ挿入します。
対象となる表はSCODE(CHAR(4)),SNAME(VARCHAR(17)),COL(NCHAR(1)),TANKA(INTEGER),及びZSURYO(INTEGER)で構成されているものとします。
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXCOLUMN 80 #define INFILE "inputf1" void abnormalend(); FILE *input ; main() { char indata[MAXCOLUMN]; char in_scode[5]; short in_sname_len; char in_sname[17]; char in_col[3]; int in_tanka; int i; EXEC SQL BEGIN DECLARE SECTION; short xinsert_num; /* 配列型の埋込み変数の宣言 */ char xscode[50][5]; /* SCODE (CHAR(4)型の列) */ /* への挿入値指定用 */ SQL TYPE IS VARCHAR(17) xsname[50]; /* SNAME(VARCHAR(17)型の列) */ /* への挿入値指定用 */ char xcol[50][3]; /* COL(NCHAR(1)型の列) */ /* への挿入値指定用 */ long xtanka[50]; /* TANKA (INTEGER型の列) */ /* への挿入値指定用 */ EXEC SQL END DECLARE SECTION; -------(HiRDBへのCONNECT処理(省略))------- input = fopen(INFILE, "r"); if (input == NULL) { fprintf(stderr, "can't open %s.", INFILE); goto FIN; } EXEC SQL WHENEVER SQLERROR PERFORM abnormalend; /* 一括挿入行数設定 (最大50行ごと) */ xinsert_num=50; while (!feof(input)) { /* 配列変数に50行分(ファイルの最終データの場合はその行まで) */ /* の入力データを設定する */ for ( i = 0; i < 50; i++) { /* ファイルからデータを読み込む */ fgets(indata, MAXCOLUMN, input); if (feof(input)){ /* ファイルの最終データの場合は,一括挿入行数にここまでの */ /* 行数を設定してfor文を抜ける */ xinsert_num= i; break; } sscanf(indata, "%4s %hd %16s %2s %8d", in_scode, &in_sname_len, in_sname, in_col, &in_tanka); /* 配列変数の要素に入力データを設定 */ strncpy(xscode[i], in_scode, 5); xsname[i].len = in_sname_len; strncpy(xsname[i].str, in_sname, 17); strncpy(xcol[i], in_col, 3); xtanka[i] = in_tanka; } /* INSERT実行 */ EXEC SQL FOR :xinsert_num INSERT INTO ZAIKO (SCODE, SNAME, COL, TANKA) VALUES (:xscode, :xsname, :xcol, :xtanka); } EXEC SQL COMMIT; printf(" *** normal ended ***\n"); FIN: if (input != NULL) { fclose(input); } EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL DISCONNECT; return(0); } void abnormalend() { int wsqlcode; if (input != NULL) { fclose(input); } wsqlcode = -SQLCODE; printf("\n*** HiRDB SQL ERROR SQLCODE = %d \n", wsqlcode); printf("SQLERRMC = %s\n", SQLERRMC); EXEC SQL ROLLBACK; EXEC SQL DISCONNECT; exit(1); }
- 例2:
-
INSERT文形式3を使用して,データ読み込み関数から読み込んだデータを,配列形式の埋込み変数に設定し,在庫表(ZAIKO)へ一括して50行分ずつ挿入します。
対象となる表はSCODE(CHAR(4)),及びROW_DATA(BINARY(3002))で構成されているものとします。
#include <stdio.h> #include <string.h> #include <stdlib.h> void abnormalend(); main() { int i,rc; EXEC SQL BEGIN DECLARE SECTION; short xinsert_num; /* 配列型の埋込み変数の宣言 */ char xscode[50][5]; /* SCODE (CHAR(4)型の列) */ /* への挿入値指定用 */ SQL TYPE IS BINARY(3004) xrow_data[50]; /* ROW_DATA(BINARY(3002)型の列)への挿入値指定用 */ /* ただし,データ長は4の倍数にする */ EXEC SQL END DECLARE SECTION; -------(HiRDBへのCONNECT処理(省略))------- EXEC SQL WHENEVER SQLERROR PERFORM abnormalend; rc = 0 ; /* 一括挿入行数設定 (最大50行ごと) */ xinsert_num=50; while (0==rc) { /* 配列変数に50行分(ファイルの最終データの場合はその行まで) */ /* の入力データを設定する */ for ( i = 0; i < 50; i++) { /* BINARYデータを読み込む:関数の詳細については省略 */ rc = get_binarydata(&xscode[i],&xrow_data[i]); if (0 != rc){ /* 入力データがなくなったら,一括挿入行数にここまでの行数を*/ /* 設定してfor文を抜ける */ xinsert_num= i; break; } } /* INSERT実行 */ EXEC SQL FOR :xinsert_num INSERT INTO ZAIKO (SCODE, ROW_DATA) VALUES (:xscode, :xrow_data); } EXEC SQL COMMIT; printf(" *** normal ended ***\n"); FIN: EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL DISCONNECT; return(0); } void abnormalend() { int wsqlcode; wsqlcode = -SQLCODE; printf("\n*** HiRDB SQL ERROR SQLCODE = %d \n", wsqlcode); printf("SQLERRMC = %s\n", SQLERRMC); EXEC SQL ROLLBACK; EXEC SQL DISCONNECT; exit(1); }
- 例3:
-
EXECUTE文形式2を使用して,ファイルから読み出したデータを配列形式の埋込み変数に設定し,在庫表(ZAIKO)へ一括して50行分ずつ挿入します。
対象となる表はSCODE(CHAR(4)),SNAME(VARCHAR(17)),COL(NCHAR(1)),TANKA(INTEGER),及びZSURYO(INTEGER)で構成されているものとします。
#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXCOLUMN 80 #define INFILE "inputf1" void abnormalend(); FILE *input ; main() { char indata[MAXCOLUMN]; char in_scode[5]; short in_sname_len; char in_sname[17]; char in_col[3]; int in_tanka; int i; EXEC SQL BEGIN DECLARE SECTION; short xinsert_num; /* 配列型の埋込み変数の宣言 */ char xscode[50][5]; /* SCODE (CHAR(4)型の列) */ /* への挿入値指定用 */ SQL TYPE IS VARCHAR(17) xsname[50]; /* SNAME(VARCHAR(17)型の列)への挿入値指定用 */ char xcol[50][3]; /* COL(NCHAR(1)型の列) への挿入値指定用 */ long xtanka[50]; /* TANKA (INTEGER型の列) への挿入値指定用 */ EXEC SQL END DECLARE SECTION; -------(HiRDBへのCONNECT処理(省略))------- input = fopen(INFILE, "r"); if (input == NULL) { fprintf(stderr, "can't open %s.", INFILE); goto FIN; } EXEC SQL WHENEVER SQLERROR PERFORM abnormalend; /* SQL前処理実行 */ EXEC SQL PREPARE INS1 FROM ‘INSERT INTO ZAIKO(SCODE, SNAME, COL, TANKA) VALUES(?,?,?,?)’; /* 一括挿入行数設定 (最大50行ごと) */ xinsert_num=50; while (!feof(input)) { /* 配列変数に50行分(ファイルの最終データの場合はその行まで) */ /* の入力データを設定する */ for ( i = 0; i < 50; i++) { /* ファイルからデータを読み込む */ fgets(indata, MAXCOLUMN, input); if (feof(input)){ /* ファイルの最終データの場合,一括挿入行数にここまでの */ /* 行数を設定してfor文を抜ける */ xinsert_num= i; break; } sscanf(indata, "%4s %hd %16s %2s %8d", in_scode, &in_sname_len, in_sname, in_col, &in_tanka); /* 配列変数の要素に入力データを設定 */ strncpy(xscode[i], in_scode, 5); xsname[i].len = in_sname_len; strncpy(xsname[i].str, in_sname, 17); strncpy(xcol[i], in_col, 3); xtanka[i] = in_tanka; } /* EXECUTE実行 */ EXEC SQL EXECUTE INS1 USING :xscode, :xsname, :xcol, :xtanka BY :xinsert_num ROWS ; } EXEC SQL COMMIT; printf(" *** normal ended ***\n"); FIN: if (input != NULL) { fclose(input); } EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL DISCONNECT; return(0); } void abnormalend() { int wsqlcode; if (input != NULL) { fclose(input); } wsqlcode = -SQLCODE; printf("\n*** HiRDB SQL ERROR SQLCODE = %d \n", wsqlcode); printf("SQLERRMC = %s\n", SQLERRMC); EXEC SQL ROLLBACK; EXEC SQL DISCONNECT; exit(1); }
- 例4:
-
EXECUTE文形式2を使用して,ファイルから読み出したデータを配列形式の埋込み変数に設定し,ユーザ定義のSQLDAを使用して在庫表(ZAIKO)へ一括して50行分ずつ挿入します。
対象となる表はSCODE(CHAR(4)),SNAME(VARCHAR(17)),COL(NCHAR(1)),TANKA(INTEGER),及びZSURYO(INTEGER)で構成されているものとします。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <pdbsqlda.h> /* ユーザ定義のSQLDAを使用するために */ /* includeする。 */ #define MAXCOLUMN 80 #define INFILE "inputf1" void abnormalend(); FILE *input ; main() { char indata[MAXCOLUMN]; char in_scode[5]; short in_sname_len; char in_sname[17]; char in_col[3]; int in_tanka; int i; /* ユーザ定義SQLDAの宣言 */ PDUSRSQLDA(4) xsqlda; EXEC SQL BEGIN DECLARE SECTION; short xinsert_num; /* 配列型の埋込み変数の宣言 */ char xscode[50][5]; /* SCODE (CHAR(4)型の列) */ /* への挿入値指定用 */ SQL TYPE IS VARCHAR(17) xsname[50]; /* SNAME(VARCHAR(17)型の列)への挿入値指定用 */ char xcol[50][3]; /* COL(NCHAR(1)型の列)への挿入値指定用 */ long xtanka[50]; /* TANKA(INTEGER型の列)への挿入値指定用 */ EXEC SQL END DECLARE SECTION; -------(HiRDBへのCONNECT処理(省略))------- input = fopen(INFILE, "r"); if (input == NULL) { fprintf(stderr, "can't open %s.", INFILE); goto FIN; } EXEC SQL WHENEVER SQLERROR PERFORM abnormalend; /* SQL前処理実行 */ EXEC SQL PREPARE INS1 FROM ‘INSERT INTO ZAIKO(SCODE, SNAME, COL, TANKA) VALUES(?,?,?,?)’; /* SQLVARの設定 */ PDSQLN(xsqlda) = 4 ; /* SQLVAR数を設定 */ PDSQLD(xsqlda) = 4 ; /* ?パラメタ数を設定 */ /* SCODE列情報設定 */ PDSQLCOD(xsqlda, 0) = PDSQL_CHAR ; /* データコード設定 */ PDSQLXDIM(xsqlda, 0) = 1 ; /* 繰り返し構造の要素数設定 */ PDSQLSYS(xsqlda, 0) = 0 ; /* 1要素の長さ(可変長文字列 */ /* 以外は0固定) */ PDSQLLEN(xsqlda, 0) = 4 ; /* データ定義長設定 */ PDSQLDATA(xsqlda, 0) = (void *)xscode ; /* データ領域アドレス設定 */ PDSQLIND(xsqlda, 0) = NULL ; /* 標識変数NULLクリア */ /* SNAME列情報設定 */ PDSQLCOD(xsqlda, 1) = PDSQL_VARCHAR ; /* データコード設定 */ PDSQLXDIM(xsqlda, 1) = 1 ; /* 繰り返し構造の要素数設定 */ PDSQLLEN(xsqlda, 1) = 17 ; /* データ定義長設定 */ PDSQLSYS(xsqlda, 1) = sizeof(xsname[0]) ; /* 1要素の長さ */ PDSQLDATA(xsqlda, 1) = (void *) xsname; /* データ領域アドレス設定 */ PDSQLIND(xsqlda, 1) = NULL ; /* 標識変数NULLクリア */ /* COL列情報設定 */ PDSQLCOD(xsqlda, 2) = PDSQL_NCHAR ; /* データコード設定 */ PDSQLXDIM(xsqlda, 2) = 1 ; /* 繰り返し構造の要素数設定 */ PDSQLSYS(xsqlda, 2) = 0 ; /* 1要素の長さ(可変長文字列 */ /* 以外は0固定) */ PDSQLLEN(xsqlda, 2) = 1 ; /* データ定義長設定 */ PDSQLDATA(xsqlda, 2) = (void *) xcol; /* データ領域アドレス設定 */ PDSQLIND(xsqlda, 2) = NULL ; /* 標識変数NULLクリア */ /* TANKA列情報設定 */ PDSQLCOD(xsqlda, 3) = PDSQL_INTEGER ; /* データコード設定 */ PDSQLXDIM(xsqlda, 3) = 1 ; /* 繰り返し構造の要素数設定 */ PDSQLSYS(xsqlda, 3) = 0 ; /* 1要素の長さ(可変長文字列 */ /* 以外は0固定) */ PDSQLLEN(xsqlda, 3) = 4 ; /* データ定義長設定 */ PDSQLDATA(xsqlda, 3) = (void *) xtanka; /* データ領域アドレス設定 */ PDSQLIND(xsqlda, 3) = NULL ; /* 標識変数NULLクリア */ /* 一括挿入行数設定 (最大50行ごと) */ xinsert_num=50; while (!feof(input)) { /* 配列変数に50行分(ファイルの最終データの場合はその行まで) */ /* の入力データを設定する */ for ( i = 0; i < 50; i++) { /* ファイルからデータを読み込む */ fgets(indata, MAXCOLUMN, input); if (feof(input)){ /* ファイルの最終データの場合,一括挿入行数にここまでの */ /* 行数を設定してfor文を抜ける */ xinsert_num= i; break; } sscanf(indata, "%4s %hd %16s %2s %8d", in_scode, &in_sname_len, in_sname, in_col, &in_tanka); /* 配列変数の要素に入力データを設定 */ strncpy(xscode[i], in_scode, 5); xsname[i].len = in_sname_len; strncpy(xsname[i].str, in_sname, 17); strncpy(xcol[i], in_col, 3); xtanka[i] = in_tanka; } /* EXECUTE実行 */ EXEC SQL EXECUTE INS1 USING DESCRIPTOR :xsqlda BY :xinsert_num ROWS ; } EXEC SQL COMMIT; printf(" *** normal ended ***\n"); FIN: if (input != NULL) { fclose(input); } EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL DISCONNECT; return(0); } void abnormalend() { int wsqlcode; if (input != NULL) { fclose(input); } wsqlcode = -SQLCODE; printf("\n*** HiRDB SQL ERROR SQLCODE = %d \n", wsqlcode); printf("SQLERRMC = %s\n", SQLERRMC); EXEC SQL ROLLBACK; EXEC SQL DISCONNECT; exit(1); }
- 例5:
-
EXECUTE文形式2を使用して,データ読み込み関数から読み込んだデータを,配列形式の埋込み変数に設定し,ユーザ定義のSQLDAを使用して在庫表(ZAIKO)へ一括して50行分ずつ挿入します。
対象となる表はSCODE(CHAR(4)),及びROW_DATA(BINARY(3002))で構成されているものとします。
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <pdbsqlda.h> /* ユーザ定義のSQLDAを使用するために */ /* includeする。 */ void abnormalend(); main() { int i,rc; /* ユーザ定義SQLDAの宣言 */ PDUSRSQLDA(4) xsqlda; EXEC SQL BEGIN DECLARE SECTION; short xinsert_num; /* 配列型の埋込み変数の宣言 */ char xscode[50][5]; /* SCODE (CHAR(4)型の列) */ /* への挿入値指定用 */ SQL TYPE IS BINARY(3004) xrow_data[50]; /* ROW_DATA(BINARY(3002)型の列)への挿入値指定用 */ /* ただし,データ長は4の倍数にする */ EXEC SQL END DECLARE SECTION; -------(HiRDBへのCONNECT処理(省略))------- EXEC SQL WHENEVER SQLERROR PERFORM abnormalend; /* SQL前処理実行 */ EXEC SQL PREPARE INS1 FROM 'INSERT INTO ZAIKO(SCODE, ROW_DATA) VALUES(?,?)’; /* SQLVARの設定 */ PDSQLN(xsqlda) = 2 ; /* SQLVAR数を設定 */ PDSQLD(xsqlda) = 2 ; /* ?パラメタ数を設定 */ /* SCODE列情報設定 */ PDSQLCOD(xsqlda, 0) = PDSQL_CHAR ; /* データコード設定 */ PDSQLXDIM(xsqlda, 0) = 1 ; /* 繰り返し構造の要素数設定 */ PDSQLSYS(xsqlda, 0) = 0 ; /* 1要素の長さ(可変長文字列 */ /* 以外は0固定) */ PDSQLLEN(xsqlda, 0) = 4 ; /* データ定義長設定 */ PDSQLDATA(xsqlda, 0) = (void *)xscode ; /* データ領域アドレス設定 */ PDSQLIND(xsqlda, 0) = NULL ; /* 標識変数NULLクリア */ /* ROW_DATA列情報設定 */ PDSQLCOD(xsqlda, 1) = PDSQL_BINARY ; /* データコード設定 */ PDSQLXDIM(xsqlda, 1) = 1 ; /* 繰り返し構造の要素数設定 */ PDSQLLOBLEN(xsqlda, 1) = 3004 ; /* データ定義長設定 */ PDSQLDATA(xsqlda, 1) = (void *) xrow_data; /* データ領域 */ /* アドレス設定 */ PDSQLIND(xsqlda, 1) = NULL ; /* 標識変数NULLクリア */ rc = 0 ; /* 一括挿入行数設定 (最大50行ごと) */ xinsert_num=50; while (0==rc) { /* 配列変数に50行分(ファイルの最終データの場合はその行まで) */ /* の入力データを設定する */ for ( i = 0; i < 50; i++) { /* BINARYデータを読み込む:関数の詳細については省略 */ rc = get_binarydata(&xscode[i],&xrow_data[i]); if (0 != rc){ /* 入力データがなくなった場合,一括挿入行数にここまでの */ /* 行数を設定してfor文を抜ける */ xinsert_num= i; break; } } /* EXECUTE実行 */ EXEC SQL EXECUTE INS1 USING DESCRIPTOR :xsqlda BY :xinsert_num ROWS ; } EXEC SQL COMMIT; printf(" *** normal ended ***\n"); FIN: EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL DISCONNECT; return(0); } void abnormalend() { int wsqlcode; wsqlcode = -SQLCODE; printf("\n*** HiRDB SQL ERROR SQLCODE = %d \n", wsqlcode); printf("SQLERRMC = %s\n", SQLERRMC); EXEC SQL ROLLBACK; EXEC SQL DISCONNECT; exit(1); }