从SQLDataReader创建访问表

时间:2013-02-05 22:03:31

标签: c# .net sql-server ms-access-2007 sqldatareader

我无法确定最佳方法。我们正在维护一个复杂的数据库,普通的业务分析师会遇到很多麻烦。另一位开发人员创建了几个存储过程作为报告,我们已根据需要将这些用户导出到excel电子表格中。

客户要求将这些结果导出到访问数据库中。

如果这是2或3列,我只需创建一个“模板”accdb文件,然后将存储过程的结果推送到那里。但是,此查询现在可以返回100多个列,并且了解客户端,将来会进行扩展。所以我试图从结果集中动态创建表......不管它是什么。

我认为/正确的方法是使用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();
  }
}

值得注意的是:

修改

这是我的“最终解决方案”。建议使用链接服务器的评论肯定会是一种更简单的方法,但有一件事阻止我做起初我没有想到的事情,数据需要存在于Access数据库中,因为用户可能会消耗数据远离他们对底层数据库的网络访问权限。因此,我一直在抨击这种方法,这就是我想出的:

请注意,我仍然愿意接受“更好的方式”的建议,但这解决了我当前的问题

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();
  }
}

1 个答案:

答案 0 :(得分:1)

这是我的“最终解决方案”。建议使用链接服务器的评论肯定会是一种更简单的方法,但有一件事阻止我做起初我没有想到的事情,数据需要存在于Access数据库中,因为用户可能会消耗数据远离他们对底层数据库的网络访问权限。因此,我一直在抨击这种方法,这就是我想出的:

请注意,我仍然愿意接受“更好的方式”的建议,但这解决了我当前的问题

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();
  }
}