1

私はこれを行うための最良の方法を決定するのに苦労しています。私たちは、平均的なビジネスアナリストが対処するのに多くの問題を抱える複雑なDBを維持しています。別の開発者は、オンデマンドでユーザー向けにExcelスプレッドシートにエクスポートしていたレポートとして、いくつかのストアドプロシージャを作成しました。

クライアントは、これらの結果をアクセスデータベースにエクスポートするように要求しました。

これが2列または3列の場合、「テンプレート」accdbファイルを作成し、そこにストアドプロシージャの結果を表示します。ただし、このクエリは現在100を超える列を返し、クライアントを知っているため、将来拡張される予定です。だから私は結果セットからその場でテーブルを作成しようとしています...それが何であれ。

私はこれを行う正しい方法は/think/を使用するSqlDataReaderことですが、適切な「SQL」風のフィールドタイプを取得する方法に固執しています。私の現在のコードは次のようになります:

static void CreateAccessTableFromReader(string tableName, SqlDataReader reader) {
  List<string> columns = new List<string>();
  string createTable = @"CREATE TABLE {0} ({1})";

  int fieldCount = reader.FieldCount;
  for (int i = 0; i < fieldCount; i++) {
    columns.Add(String.Format("[{0}] {1}({2})",
      //column name (this seems to be right)
      reader.GetName(i), 
      //column type __(this is wrong.. I want 'VARCHAR, INT, etc')__
      reader.GetProviderSpecificFieldType(i),
      //column size (e.g. the numeric part of VARCHAR(15))
      reader.???
    ));
    //right now I'm getting results from the above line like:
    //[ColumnName] System.Data.SqlTypes.SqlString
    //and I'm looking for something like:
    //[ColumnName] VARCHAR(15)
  }
  using (var cmd = conn_Access.CreateCommand()) {
    cmd.CommandType = CommandType.Text;
    cmd.CommandText = String.Format(createTable, tableName, String.Join(", ", columns));
    cmd.ExecuteNonQuery();
  }
}

注目に値する:

編集

これが私の「最終的な解決策」です。リンクサーバーを使用することを提案するコメントは確かに簡単なアプローチでしたが、最初は思いもよらなかったことができなかったことが1つありました。ユーザーが消費する可能性があるため、データはAccessDBに存在する必要があります。基盤となるDBへのネットワークアクセスが可能な場所から離れたデータ。そういうものとして、私はこのアプローチを強打し続けました、そしてこれが私が思いついたものです:

私はまだ「より良い方法」の提案を受け入れることに注意してください、しかしこれは私の現在の問題を解決します

static void CreateTableFromReader(string tableName, SqlDataReader reader) {
  List<string> columns = new List<string>();
  string createTable = @"CREATE TABLE {0} ({1})";

  var dt = reader.GetSchemaTable();
  foreach (DataRow dr in dt.Rows) {
    switch (dr["DataTypeName"].ToString().ToLower()) {
      case "varchar":
        columns.Add(String.Format("[{0}] {1}({2})",
          dr["ColumnName"],
          dr["DataTypeName"],
          dr["ColumnSize"]
        ));
        break;
      case "money": //i know this is redundant but being explicit helps clarity sometimes
      case "date":
      case "integer":
      default:
        columns.Add(String.Format("[{0}] {1}",
          dr["ColumnName"],
          dr["DataTypeName"]
        ));
        break;
    }
  }
  using (var cmd = conn_Access.CreateCommand()) {
    cmd.CommandType = CommandType.Text;
    cmd.CommandText = String.Format(createTable, tableName, String.Join(", ", columns));
    cmd.ExecuteNonQuery();
  }
}
4

1 に答える 1

1

これが私の「最終的な解決策」です。リンクサーバーを使用することを提案するコメントは確かに簡単なアプローチでしたが、最初は思いもよらなかったことができなかったことが1つありました。ユーザーが消費する可能性があるため、データはAccessDBに存在する必要があります。基盤となるDBへのネットワークアクセスが可能な場所から離れたデータ。そういうものとして、私はこのアプローチを強打し続けました、そしてこれが私が思いついたものです:

私はまだ「より良い方法」の提案を受け入れることに注意してください、しかしこれは私の現在の問題を解決します

static void CreateTableFromReader(string tableName, SqlDataReader reader) {
  List<string> columns = new List<string>();
  string createTable = @"CREATE TABLE {0} ({1})";

  var dt = reader.GetSchemaTable();
  foreach (DataRow dr in dt.Rows) {
    switch (dr["DataTypeName"].ToString().ToLower()) {
      case "varchar":
        columns.Add(String.Format("[{0}] {1}({2})",
          dr["ColumnName"],
          dr["DataTypeName"],
          dr["ColumnSize"]
        ));
        break;
      case "money": //i know this is redundant but being explicit helps clarity sometimes
      case "date":
      case "integer":
      default:
        columns.Add(String.Format("[{0}] {1}",
          dr["ColumnName"],
          dr["DataTypeName"]
        ));
        break;
    }
  }
  using (var cmd = conn_Access.CreateCommand()) {
    cmd.CommandType = CommandType.Text;
    cmd.CommandText = String.Format(createTable, tableName, String.Join(", ", columns));
    cmd.ExecuteNonQuery();
  }
}
于 2013-02-06T16:46:58.307 に答える