1

MS Access データベースのすべてのテーブルとその行数をグリッド ビューで一覧表示したいと考えています。次のようにクエリを使用しています。

SELECT MSysObjects.Name, CLng(DCount('*',[name])) AS RecordCount
    FROM MSysObjects WHERE (((MSysObjects.Type)=1)
    AND (MSysObjects.Name NOT LIKE 'MSys*')) 
    ORDER BY MSysObjects.Name;

MS Access Query ペインでは、これは問題なく機能します。しかし、.NET で OleDbCommand オブジェクトを介してクエリを実行すると、クエリによって結果セットが生成されますが、MSysNavPaneGroupCategories を含むデータの行が取得されます。この行は、次のことを試みると常にエラーをスローします。

 DataRow row = null;
 do
 {
    row = dt.NewRow();
    row["TableName"] = (string)dr["Name"];
    row["RecordCount"] = (int)dr["RecordCount"]; // Fails here when dr["Name"]==MSysNavPaneGroupCategories
    dt.Rows.Add(row);
 } while (dr.Read());

エラーメッセージは次のとおりです。

System.InvalidOperationException が処理されませんでした。

プロバイダは Int32 値を特定できませんでした。たとえば、行が作成されたばかりで、Int32 列の既定値が使用できず、コンシューマーがまだ新しい Int32 値を設定していません。ソース="System.Data"

したがって、私の回避策は、TEMPテーブルを作成し、代わりにそこから読み取ることです(または、列のデフォルト値を設定します...これにより、エラーは克服されますが、結果セットに不正なテーブルが含まれます)。

何が起きてる?MSysNavPaneGroupCategories は、結果セットに含まれていないはずです。

MSysNavPaneGroupCategories システム テーブルに関する情報はあまりありません。

この URLは、MSysNavPaneGroupCategories が 3 つのシステム テーブルの 1 つであることを示しています。

ナビゲーション ペイン内のすべてのコンテンツを定義します。

.. Access 2007 で。

このマイクロソフトのURLは言う

Microsoft Office Access 2007 の新機能であるナビゲーション ウィンドウは、すべてのデータベース オブジェクト (データベース オブジェクト: Access データベースには、テーブル、クエリ、フォーム、レポート、ページ、マクロ、 Access プロジェクトには、フォーム、レポート、ページ、マクロ、モジュールなどのオブジェクトが含まれています)、レポートを実行したり、テーブルに直接データを入力したりします。

... Access 2007 で。

このテーブルが Access 2007 の機能であるのに Access 2K データベース テーブル リストに表示されるのはなぜですか? また、条件に一致しないクエリに表示されるのはなぜですか?

4

1 に答える 1

1

Jet のネイティブ データ アクセス ライブラリである DAO は、TableDefs コレクションを提供します。これにより、レコード数の取得とデータのグリッドへの挿入が容易になります。このようなものは、VBA でジョブを実行します (これで開始できます。これはエア コードです)。

  Dim db As DAO.Database
  Dim tdf As DAO.TableDef
  Dim strTableName As String
  Dim strConnect As String
  Dim strType As String 
  Dim strDatabase As String
  Dim strConnectType As String

  Set db = DBEngine.OpenDatabase("[path/filename of MDB/ACCDB file]")
  For Each tdf In db.TableDefs
    If (tdf.Attributes And dbSystemObject) = 0 Then ' examine only non-system tables
       strTableName = tdf.Name
       If Len(tdf.Connect) > 0 Then
          strConnect = tdf.Connect
          strDatabase = Split(strConnect, "=")(1)
       End If
       If (tdf.Attributes And dbAttachedTable) Then ' linked Jet/ACE table
          Debug.Print strTableName & ": " & DBEngine.OpenDatabase(strDatabase).TableDefs(strTableName).RecordCount
       ElseIf (tdf.Attributes And dbAttachedODBC) Then ' ODBC table
          Debug.Print strTableName & ": " & DBEngine(0)(0).OpenRecordset("SELECT COUNT(*) FROM " & strTableName)(0)
       Else ' local table
          Debug.Print strTableName & ": " & tdf.RecordCount
       End If
    End If
  Next tdf
  Set tdf = Nothing
  db.Close
  Set db = Nothing

上記のコードは Jet/ACE および ODBC データ ソースのみを処理し、Excel スプレッドシート、テキスト/CSV、または DBF ファイルは処理しませんが、これらが必要な場合は、ODBC ケースを CASE ELSE にして、それらすべてを SELECT COUNT(* )。

上記は、最初にシステム以外のすべての TableDefs をループし、すべての一意のバックエンドのリストを取得することで明らかに最適化できるため、Jet/ACE バックエンドごとに 1 回だけ OpenDatabase を実行する必要があります。また、ODBC データ ソースへの単一の ODBC 接続を使用するか、ODBC 接続文字列を ADO に変換して、必要に応じてより多くの情報を取得することもできます。

さて、これが良いアイデアであるかどうかは、特定の状況によって異なります。すべての TableDefs には、Jet/ACE によってテーブルのメタデータの一部として維持される RecordCount プロパティがあります。ただし、ローカル テーブルでのみすぐにアクセスできます。つまり、リンクされたテーブルでは機能しません。そのため、接続された Jet/ACE テーブルは、バックエンド データベースを開くことに基づいてチェックされます。

しかし、繰り返しになりますが、これが最善の方法である、あるいは良い方法でさえあると私は必然的に言っています。主に RecordCount プロパティを利用するのが好きだからです (これは SELECT COUNT(*) FROM テーブルによって返されるものだと思いますが、そうしないのでより高速です)。レコードセットを開くオーバーヘッドがあります)、使用可能な場合。

于 2010-01-08T05:45:08.503 に答える