ODBC使用でAccessのデータソースを開くと・・・。

[戻る]
Takeshi [E-Mail] 2002/04/18(木) 16:55:02
■動作環境    : WindowsNT4.0
■開発環境    :Visual C++6.0(SDI形式)
■データベース:Access2000(ODBC接続)

  質問します。

[ファイル]:???View.cpp
[ク ラ ス]:void C???View::OnInitialUpdate()

// レコードを開く(双方向非同期,データソース名,読取専用)
レコードセット.Open(CRecordset::snapshot,"データソース",CRecordset::readOnly);

あらかじめ"Access"で作成した"MDB"をODBCのデータソースに設定した上で、
レコードを操作しようとしているのですが、これを実行させると
"データソースの指定を求めるダイアログ"が現れます。
そこで該当するMDBファイルを指定してOKすると
「パラメータが少な過ぎます。3を指定して下さい。」という警告ダイアログが出ます。

これは一体何のパラメータが少ないと言っているのでしょうか?

また、ODBCの設定時にデータソース(MDBファイル)を指定したはずなのに、
再度実行時に聞かれるのはどういう事でしょうか?

宜しくお願いします。

dairygoods 2002/04/19(金) 09:57:28
> // レコードを開く(双方向非同期,データソース名,読取専用)
> レコードセット.Open(CRecordset::snapshot,"データソース",CRecordset::readOnly);

レコードセットのOpen関数の第2パラメータは、SQL文字列ですよ。

Takeshi [E-Mail] 2002/04/19(金) 10:17:57
  お世話になっております。

MicrosoftのHPにある "MSDNライブラリ" の中に
MFCの関数一覧があるんですが、そこを参考にしました。

http://www.microsoft.com/japan/developer/library/default.asp?
URL=/japan/developer/library/vcmfc/_mfc_crecordset.3a3a.open.htm

  これによると、CRecordset::Open の引数っていうのは
CRecordset::Open(オープン形式,文字列へのポインタ,オプション)

それで第二引数の "文字列へのポインタ" は、

・NULL
・テーブル名
・SQL文
・組込みクエリの名前を指定するCALL文

のいづれかになっていたので、テーブル名(データソース)を入れたのですが。
間違っているんでしょうかね?

dairygoods 2002/04/19(金) 10:55:37
なるほど、テーブル名も可能なのですね。
しかし、テーブル名とデータソース名は違います。
テーブル名は、mdbの中にあるテーブルの名前です。

データソースが固定ならば、クラスウィザードで
CRecordsetの派生クラスを作れば勝手にデータソースと関連付けてくれます。

データソースが可変の場合は、
先にCDatabaseをOpenし(このときにデータソースを指定)、
CRecordsetのコンストラクタにそれを渡す必要があります。

CDatabaseがデータソースを表すクラスで、
CRecordsetは検索結果一覧を表すクラスです。

Takeshi 2002/04/19(金) 11:38:55
  お世話になりまする。

そうですね、テーブル名とデータソース名を勘違いしていたかも知れません。
ですがテーブル名に変更したら、警告メッセージの内容が変わりました。
「パラメータが少な過ぎます。14を指定して下さい。」という警告ダイアログが出ます。
前は 3 で今度は 14 。一体何を指している数字なのでしょうか?

  ちなみに、CRecordset型のクラスは ClassWizard で既に追加しています。
ただ、CRecordset.cpp にも CRecordset.h にもデータソース名は記載されてませんでした。
この状態でもちゃんと関連付けがなされているのでしょうかね?
今はデータソースは一個だけで固定です。

dairygoods 2002/04/19(金) 11:47:28
う〜ん。
以下はOKですか?
・追加したクラスのGetDefaultConnectが返すデータソース名
・同じくGetDefaultSQLが返すテーブル名
・上記テーブル名と開こうとしているテーブルが一致しているか

Takeshi 2002/04/19(金) 13:14:46
  お世話になっておりまする。


追加したクラス(CXxxRecordset)の内容はこうです。

CString CXxxRecordset::GetDefaultConnect()
{
    return _T("ODBC;DSN=");
}

CString CXxxRecordset::GetDefaultSQL()
{
    return _T("");
}

なぜか "DSN" も "_T" も空白でした。

DSN = データソースファイル名

_T = 開きたいテーブル名

を設定してやってみます。
ありがとうございました。

Takeshi 2002/04/19(金) 13:59:01
  残念ながら解決とは行きませんでした。

それぞれに値を入れて実行してみましたが、

「データソース名および指定された既定のドライバが見つかりません。」となります。

"データソース名"、"データソース名.dsn"の両方試しましたが、駄目でした。
ファイルをVC++のプロジェクトのあるフォルダ(Debug)に入れてみましたが結果は同様でした。

もう後はどこをチェックすればいいのか、分からなくなってきました。

不良PG 2002/04/19(金) 15:17:52
>CString CXxxRecordset::GetDefaultConnect()
>{
>    return _T("ODBC;DSN=");
    return _T("ODBC;DSN=MS Access Database");
>}

>CString CXxxRecordset::GetDefaultSQL()
>{
>    return _T("");
    return _T("[テーブル名]");
>}

では?

不良PG 2002/04/19(金) 15:25:35
追加です
ファイル名も指定できます。

>return _T("ODBC;DSN=MS Access Database");
return _T("ODBC;DSN=MS Access Database;DBQ=データベース.mdb");

Takeshi 2002/04/19(金) 15:41:12
  お世話になります。

テーブル名を[]で閉じるってところで、これかなと思いましたが駄目でした。
データソース名、ファイル名も試しました。

「データソース名および指定された既定のドライバが見つかりません。」

のダイアログが表示されるままです。なかなか難しいですね。

私も色々試しているのですが・・・。

不良PG 2002/04/19(金) 15:50:13
>レコードセット.Open(CRecordset::snapshot,"データソース",CRecordset::readOnly);
レコードセット.Open(CRecordset::snapshot,NULL,CRecordset::readOnly);
これでも駄目です?

実際にどのようなコードを書いてますか?

Takeshi 2002/04/19(金) 16:14:21
  一度、記述したコードを全部ここに載せますね。ひょっとしたら私の気づいていない
基本的な穴が空いているかも知れませんし。

まずは、ClassWizardで作成したCRecordsetのクラスです。
"Xxx"はプロジェクトの名前が入ります。

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
■ファイル名:XxxRecordset.cpp

CString CXxxRecordset::GetDefaultConnect()
{
    return _T("ODBC;DSN=MS Access Database;DBQ=XxxDataSource.mdb");
}

CString CXxxRecordset::GetDefaultSQL()
{
    return _T("[TableName]");
}

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
■ファイル名:XxxView.cpp

void CXxxtView::OnInitialUpdate()
{
    CFormView::OnInitialUpdate(); 
    GetParentFrame()->RecalcLayout();
    ResizeParentToFit();

// ここから

    // 文字列型OBJを宣言
    CString string_CS;

    // レコードセット型OBJを宣言
    CXxxRecordset record_RS;

    // コントロールのポインタを宣言
    CComboBox* ComboBox_ctrl;

    // コントロール(IDC_COMBO_AP)を取得してポインタに設定
    ComboBox_ctrl = (CComboBox*)GetDlgItem(IDC_COMBO_AP);

    // テーブルを開く(双方向非同期,データソース,読取専用)
    record_RS.Open(CRecordset::snapshot,"[LANGUAGE]",CRecordset::readOnly);

    // 先頭レコードに移動
    record_RS.MoveFirst();

    // レコードの終端までループ
    while(record_RS.IsEOF() == 0)
    {
        // カレントレコードを文字列型OBJに取得
        record_RS.GetFieldValue("[TableName]",string_CS);

        // 文字列型OBJからコントロール(IDC_COMBO_AP)にレコードを追加
        ComboBox_ctrl ->AddString(string_CS);

        // 次レコードに移動
        record_RS.MoveNext();
    }

    // テーブルを閉じる
    record_RS.Close();

// ここまで

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
  これで記述は全部です。

フォームの表示と同時に、テーブルからレコードを読み込んでコンボボックスに
追加しています。レコードの終端まで追加したら終わりです。

宜しくお願いします。

Takeshi 2002/04/19(金) 16:25:50
先ほどの、

    record_RS.Open(CRecordset::snapshot,NULL,CRecordset::readOnly);

これもやりましたけど、同じ警告メッセージですね。

Takeshi 2002/04/19(金) 16:29:00
  ※コード全文のところで、訂正です。


// テーブルを開く(双方向非同期,データソース,読取専用)
    record_RS.Open(CRecordset::snapshot,"[LANGUAGE]",CRecordset::readOnly);

                                   ↓

    record_RS.Open(CRecordset::snapshot,"[TableName]",CRecordset::readOnly);


が正解です。[LANGUAGE]と[TableName]は、[TableName]で統一は取れています。
そこの相違が原因ではないです。

不良PG 2002/04/19(金) 16:32:43
>record_RS.GetFieldValue("[TableName]",string_CS);
なぜフィールド名ではなく、テーブル名なのですか?

エラーが出るのは、どの個所でしょう?
デバッカで追えば分るはずですが・・

Takeshi 2002/04/19(金) 16:50:11
  お世話になっております。

すいません、

record_RS.GetFieldValue("[TableName]",string_CS);

の件ですが、テーブル名 と フィールド名は同じなんです。


  それから、エラーになる訳ではないんです。

record_RS.Open(CRecordset::snapshot,"[TableName]",CRecordset::readOnly);

このオープンのところで、警告ダイアログが出るのは確認してます。
あくまで警告なので、フォームが表示されて正常に起動したようには見えます。
ただ、読み込みたいデータは表示されていませんが・・・。

クリリン 2002/04/19(金) 17:31:50
余計な口出しかもしれませんが、データベースを使用する場合、何処でエラーが発生しているか
わかりにくいので、エラートラップ処理[try,catch]を使用してエラーの内容を確認およびエラ
ー処理を追加してみてはいかがでしょうか?
ある程度のエラー内容がわかると思いますよ。

余談ですが[データベース.mdb]を一度フルパスで行ってみてはいかがでしょうか?
まぁ、そんなミスはしてないとは思いますが、焦っていると結構、初歩的なミスを犯していたり
するものですからね・・・(~_~;)

ちなみにADOでの処理ならば、コンボボックスにデータを格納までのソースは記述できるので
すが、あいにく、ODBC経由では行っていないので・・・

不良PG 2002/04/19(金) 17:35:38
コントロールパネルの「データソース(ODBC)」のユーザーデータソースに「MS Access 
Database」は入っていますか?

Takeshi 2002/04/19(金) 18:03:33
  クリリンさん、ありがとうございます。参考にさせて頂きます。


  不良PGさん、コントロールパネルの「データソース(ODBC)」の
ユーザーDSN は空でした。

これについては、システムDSN を設定していたので
それでOKだと思っていました。ユーザーDSN も必要なんですか?

でもでも、ユーザーDSNを設定したら
警告メッセージは無くなって、別のエラーになったので良かったです。
お蔭様で一つ前進しました。今度は「FROM句の構文エラー」らしいですが、
しばらく自分で考えてみます。解決できないようならまた質問させて頂きます。
ありがとうございました。

クリリン 2002/04/19(金) 18:17:27
テーブル名 と フィールド名 が同じなのですよね?
こうしてはいかがでしょうか

select t1.データ from データ t1

としてはいかがでしょうか?もしかしたら、名前の解決が上手くいっていないのではないでしょ
うか?
今まで同じテーブル名 と フィールド名 をした事がないので確信が持てませんが・・・

でも、これは、開発するのであれば、問題ですね。
というのも、第三者がコードを見た時に混乱するからです。また、時間が経つと自分自身も忘れ
てしまい、修正が一苦労しますよ!
参考までに私は、テーブル名は頭に[TBL_TEST]や[MST_TEST]みたいにしています。

えらそうな事言ってすいません。m(__)m

Takeshi 2002/04/19(金) 22:19:45
  こんばんは、ありがとうございます。

ご忠告通りテーブル名とフィールド名は分ける事にします。
その方が余計な混乱をしないで済みそうです。

[TBL_XXX]、[ROW_XXX] などと区別していきます。
またお願いします。

Takeshi 2002/04/23(火) 11:32:58
■動 作 環 境:WindowsNT4.0
■開 発 環 境:Visual C++6.0
■データベース:Access2000

  お世話になってます。
実行時に 「FROM句の構文エラーです」 となるのは、


●ファイル CXxxRecordset.cpp の

CString CXxxRecordset::GetDefaultSQL()
{
    return _T("select FIELD_NAME from TABLE_NAME");
}

このデフォルトSQLの from が、間違っているという事ですよね?
確認するのはここだけでいいんでしょうか。

クリリン 2002/04/23(火) 12:11:50
構文に間違いはないと思われます。
とりあえず、スクリプト文をDB内でチェックしてみてはいかがでしょうか?
たとえば、ACCESSであれば、クエリーでSQLモードにして、スクリプト文を実行。
SQL Server であれば、クエリーアナライザなど、実行結果が出力されるツールを使用して、
結果が返ってくるかどうかしてみてはいかがでしょうか?
案外、テーブル名やフィールド名、検索条件の入力ミスなどが発見できますよ。
また、スクリプトをプログラム内で作成しているのであれば、デバッグでスクリプトが生成され
た処でブレイクして、スクリプト文をコピーする・・・という手もあります。
ま、他にも方法はありますけど、手っ取り早い方法です。

dairygoods 2002/04/23(火) 12:23:59
GetDefaultSQLはOpenの第二引数にNULLを指定したときに
デフォルトで使うSQLですので、
Openの第二引数に何か指定している場合は、そちらも確認が必要です。

Takeshi 2002/04/23(火) 15:35:52
[[解決]]
  お世話になっております。

"SQLモード" というのは、[表示(V)]の[SQLビュー(Q)]の事ですか?
これを選ぶとSQL文が表示されましたが。これで結果が正しければOKって事ですか?

  Q.ところで意味が分からない言葉だったんですが、"スクリプト文" とは何ですか?



  でもとりあえず、レコードの Open を NULL にして、
-------------------------------------------------------------------------------
▼ファイル名:XxxView.cpp

MyRecordset.Open(CRecordset::snapshot,NULL,CRecordset::readOnly);

-------------------------------------------------------------------------------
▼ファイル名:XxxRecordset.cpp

CString CExpertRecordset::GetDefaultConnect()
{
    return _T("ODBC;DSN=MS Access Database;DBQ=xxx.mdb");
}

CString CExpertRecordset::GetDefaultSQL()
{
    return _T("SELECT フィールド名 FROM テーブル名");
}

-------------------------------------------------------------------------------

GetDefaultConnect,GetDefaultSQL の記述を見に行くようにしたら、
レコードをうまくOpenできました。
二つの場所の記述に整合性が無かったのが原因だと思います。
NULL にしてしまうのもひとつの手なんですね。

   dairygoodsさん、クリリンさん、ありがとうございました。

クリリン 2002/04/23(火) 16:11:53
>"SQLモード" というのは、[表示(V)]の[SQLビュー(Q)]の事ですか?
はい、そうです。
>"スクリプト文" とは何ですか?
SQLスクリプト文を指します。
この、[SELECT フィールド名 FROM テーブル名]も、SQLスクリプト文なのです。

Takeshi 2002/04/25(木) 10:27:54
[[解決]]
  お世話になってます。

SQLスクリプト文 = SQL文 で宜しいんですね?
SQL文も勉強して使いこなせるようになりたいですね。

全ての基本は SELECT文 みたいですが。
また宜しくお願いします。

古いスレッドには追加発言できません。