Windows環境にてC言語やC++でODBCを使うには2

Windows環境にてC言語やC++でODBCを使うには1
http://sato-si.at.webry.info/200503/article_11.html
の続きです。

実際のC言語/C++でのプログラムのコーディングからです。

C:\test.xls を作成し,中身に次のような簡単な表を作成し,この表を印刷範囲に設定します。


+------+------+
| 名前 | 年齢 |
+------+------+
| やま |    27|
+------+------+
| たま |     2|
+------+------+
| くろ |     4|
+------+------+


※これはコンソールアプリケーションとして作成していますが,
通常のWindowsアプリケーションでも同じです。

// ODBCで必要な include 文
#include <windows.h>
#include <sql.h>
#include <sqlext.h>

// printf 使うので,これもinclude
#include <stdio.h>

// ODBCで必要なライブラリ(インポートライブラリ)
#pragma comment(lib, "odbc32.lib")

int main()
{
  //ODBCで最低限必要なハンドル
  HENV henv;    // ODBC環境のハンドル
  HDBC hdbc;    // ODBC接続中のハンドル
  HSTMT hstmt;    // SQL文実行中のハンドル(クエリ実行や結果のテーブルの値取得など)
  RETCODE rc;    // 関数の処理結果(戻り値)を保持するための変数

  // ODBCドライバ接続用の文字列 (ODBCで開くエクセルファイルも指定できる)
  TCHAR *ucConnectStr = "Driver={Microsoft Excel Driver (*.xls)};dbq=C:\\test.xls";

  // ODBCドライバ接続用の文字列の完全版の取得用文字列 と その長さ
  TCHAR ucOutConnectStr[1024];  // 最低でも1024バイト必要です
  SQLSMALLINT pcbConOut = 0;

  // SQL文実行時に利用する文
  UCHAR select[] = "SELECT * FROM [Sheet1$Print_Area]";
   // [シート名$範囲・範囲名] (エクセルの印刷範囲をテーブルとみなす)

// カラム数取得時に使う変数
  SQLSMALLINT nresultcols = 0, i; // カラム数と,forループ変数

// カラム詳細情報取得時に使う変数
  SQLCHAR colname[128]; // カラム名
  SQLSMALLINT colnamelen = 0; // カラム名の文字数
  SQLSMALLINT coltype = 0; // データの型
  SQLUINTEGER collen; // このカラムの領域サイズ(バイト単位)
  SQLSMALLINT scale = 0; // たとえば,NUMERIC(10,3)なら, 3が入る。使われないことも多い
  SQLSMALLINT nullable = 0; // NULLが可能かどうか

  // SQL結果取得用のバッファ
  UCHAR data[30][256]; // データ格納用
  SQLINTEGER datastrlen[30]; // 帰ってきた文字列長

  // 初期化処理
  SQLAllocEnv(&henv);    // ODBC環境のためのメモリ(作業領域)確保
  SQLAllocConnect(henv, &hdbc);    // ODBC接続中状態のメモリ(作業領域)確保
  rc = SQLDriverConnect(hdbc, NULL, (SQLTCHAR*)ucConnectStr, lstrlen(ucConnectStr), (SQLTCHAR*)ucOutConnectStr, sizeof(ucOutConnectStr), &pcbConOut, SQL_DRIVER_NOPROMPT ); // パラメータを文字列で指定してODBCドライバに接続する

  // ODBC接続時に使った実際の文字列を出力
  ucOutConnectStr[pcbConOut] = '\0';
  printf("%s\n",ucOutConnectStr);

  // もし,接続に失敗したら,終了する。
  if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
    SQLDisconnect(hdbc);  // ODBC接続を切断
    SQLFreeConnect(hdbc);  // ODBC接続状態のメモリを開放
    SQLFreeEnv(henv);  // ODBC環境のメモリを開放
    return -1;  // プログラム終了(main関数から出る)
  }

  SQLAllocStmt(hdbc, &hstmt);  // ステートメント開始

  // ここから,hstmt を使ってSQLが使えます♪

  // SQL文を実行
  if (SQLExecDirect(hstmt, select, SQL_NTS) != SQL_SUCCESS) {
    SQLFreeStmt(hstmt, SQL_DROP); // SQL文の実行の後始末,メモリの開放
    SQLDisconnect(hdbc);  // ODBC接続を切断
    SQLFreeConnect(hdbc);  // ODBC接続状態のメモリを開放
    SQLFreeEnv(henv);  // ODBC環境のメモリを開放
    return -2;
  }

  // SQL文の結果のテーブルをとりたいときは以下の文を使います。(いらない場合は使いません。)

  // SQL文の結果のテーブルのカラム(項目)数をnresultcolsに取得
  SQLNumResultCols(hstmt, &nresultcols);

  for (i = 0; i < nresultcols; i++) {
    SQLDescribeCol(hstmt, (UWORD)(i + 1), colname,
      (SWORD)sizeof(colname),
      &colnamelen, &coltype, &collen, &scale,
      &nullable);

    printf("%s\t", colname);

  // フィールドごとにと変数を関連付けする
    SQLBindCol(hstmt, (UWORD)(i + 1), SQL_C_CHAR, data[i],
      sizeof(data[0]), &datastrlen[i]);
  }
  printf("\n");

// データの取り込み(1ループ1レコード
  while (TRUE) {
    rc = SQLFetch(hstmt);
    if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) {
      for (i = 0; i < nresultcols; i++) {
        if (datastrlen[i] == SQL_NULL_DATA) {
          printf("null\t");
        } else {
          data[i][datastrlen[i]] = '\0';
          printf("%s\t", data[i]);
        }
      }
    } else {
      break;
    }
    printf("\n");
  }

  // 後始末
  SQLFreeStmt(hstmt, SQL_DROP); // SQL文の実行の後始末,メモリの開放
  SQLDisconnect(hdbc);  // ODBC接続を切断
  SQLFreeConnect(hdbc);  // ODBC接続状態のメモリを開放
  SQLFreeEnv(henv);  // ODBC環境のメモリを開放

  return 0;
}


以上のプログラムを正しく実行できた場合は,


DBQ=C:\test.xls;Driver={Microsoft Excel Driver (*.xls)};DriverId=790;MaxBufferSi
ze=2048;PageTimeout=5;
名前 年齢
やま 27.0
たま 2.0
くろ 4.0



といった感じの結果が出てきます。

これで,とりあえず,ODBCがつかえると思います。

エクセルODBC応用

例1 シート全体を1つのテーブルとするなら,
UCHAR select[] = "SELECT * FROM [Sheet1$]";

例2 一部のセルを選択 Sheet1のA3からC30の範囲を選ぶなrら
UCHAR select[] = "SELECT * FROM [Sheet1$A3:C30]";

例3 セルに名前を定義していると,それをテーブル名として指定できます。
たとえば,領域を「集計表」として,定義しておくと,
UCHAR select[] = "SELECT * FROM [集計表]";
という風にもできます。
ちなみに,この名前の作り方は,Excelのメニューの「挿入(I)」 - 「名前(N)」-「定義(D)...」でできます。

実際のプログラムでは,SQL文の結果テーブルのデータ取得の方法を
もう少し工夫したほうがよいでしょう。それは,次回の
Windows環境にてC言語やC++でODBCを使うには3
http://sato-si.at.webry.info/200601/article_5.html
で説明します。

"Windows環境にてC言語やC++でODBCを使うには2" へのコメントを書く

お名前
メールアドレス
ホームページアドレス
コメント