【问题标题】:How can I get the field names of a database table?如何获取数据库表的字段名称?
【发布时间】:2010-10-25 20:51:52
【问题描述】:

如何获取 MS Access 数据库表的字段名称?

是否有我可以使用的 SQL 查询,或者是否有 C# 代码来执行此操作?

【问题讨论】:

  • 我建议的解决方案不仅限于 MS Access 数据库。

标签: c# database ms-access


【解决方案1】:

使用IDataReader.GetSchemaTable()

这是一个实际的示例,它访问表架构并以 XML 格式将其打印出来(只是为了查看您获得的信息):

class AccessTableSchemaTest
{
    public static DbConnection GetConnection()
    {
        return new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=..\\Test.mdb");
    }

    static void Main(string[] args)
    {
        using (DbConnection conn = GetConnection())
        {
            conn.Open();

            DbCommand command = conn.CreateCommand();
            // (1) we're not interested in any data
            command.CommandText = "select * from Test where 1 = 0";
            command.CommandType = CommandType.Text;

            DbDataReader reader = command.ExecuteReader();
            // (2) get the schema of the result set
            DataTable schemaTable = reader.GetSchemaTable();

            conn.Close();
        }

        PrintSchemaPlain(schemaTable);

        Console.WriteLine(new string('-', 80));

        PrintSchemaAsXml(schemaTable);

        Console.Read();
    }

    private static void PrintSchemaPlain(DataTable schemaTable)
    {
        foreach (DataRow row in schemaTable.Rows)
        {
            Console.WriteLine("{0}, {1}, {2}",
                row.Field<string>("ColumnName"),
                row.Field<Type>("DataType"),
                row.Field<int>("ColumnSize"));
        }
    }

    private static void PrintSchemaAsXml(DataTable schemaTable)
    {
        StringWriter stringWriter = new StringWriter();
        schemaTable.WriteXml(stringWriter);
        Console.WriteLine(stringWriter.ToString());
    }
}

兴趣点:

  1. 不要通过给出始终评估为假的 where 子句来返回任何数据。当然,这只适用于您对数据不感兴趣的情况:-)。
  2. 使用 IDataReader.GetSchemaTable() 获取包含有关实际表的详细信息的 DataTable。

对于我的测试表,输出是:

ID, System.Int32, 4
Field1, System.String, 50
Field2, System.Int32, 4
Field3, System.DateTime, 8
--------------------------------------------------------------------------------
<DocumentElement>
  <SchemaTable>
    <ColumnName>ID</ColumnName>
    <ColumnOrdinal>0</ColumnOrdinal>
    <ColumnSize>4</ColumnSize>
    <NumericPrecision>10</NumericPrecision>
    <NumericScale>255</NumericScale>
    <DataType>System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</DataType>
    <ProviderType>3</ProviderType>
    <IsLong>false</IsLong>
    <AllowDBNull>true</AllowDBNull>
    <IsReadOnly>false</IsReadOnly>
    <IsRowVersion>false</IsRowVersion>
    <IsUnique>false</IsUnique>
    <IsKey>false</IsKey>
    <IsAutoIncrement>false</IsAutoIncrement>
  </SchemaTable>
  [...]
</DocumentElement>

【讨论】:

  • 'conn.Close()' 不是多余的吗,因为连接是在 'using' 构造中创建的,当执行时仍然存在构造时会关闭连接?
【解决方案2】:

这将适用于 sql server 2005 及更高版本:

select * from INFORMATION_SCHEMA.COLUMNS 
where TABLE_Name='YourTableName'
order by ORDINAL_POSITION

【讨论】:

  • @Gold,为问题添加“访问”标签!
  • 这在访问中不起作用。你能解释一下 INFORMATION_SCHEMA 是什么吗?
  • @Uzair Ali,我在 OP 指定他们在 Access 数据库中工作之前回答了这个问题。我的答案是专门针对 SQL Server 2005 及更高版本以及支持信息架构 ANSI 标准的数据库。显然,您的 Access 数据库版本不支持信息架构 ANSI 标准。信息模式是一组 ANSI 标准的只读视图,它提供有关数据库中所有表、视图、列和过程的信息。 en.wikipedia.org/wiki/Information_schema
【解决方案3】:

运行此查询:

select top 1 *
From foo

然后遍历结果集中的列表字段(和返回值)以获取字段名称。

【讨论】:

  • 如果您只需要列 names ,那么这种快速而肮脏的方法就可以在 IMO 中使用。请注意,您可以添加 WHERE 0=1(或类似值)以确保不返回任何数据。
  • 如果您定义了字幕,这将不起作用。而是显示标题。
【解决方案4】:

您是在问如何获取数据库中表的列名?

如果是这样,它完全取决于您使用的数据库服务器。

在 SQL 2005 中,您可以从 INFORMATION_SCHEMA.Columns 视图中进行选择

SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable'

在 SQL 2000 中,您可以将 SysObjects 加入 SysColumns 以获取信息

SELECT     
    dbo.sysobjects.name As TableName
    , dbo.syscolumns.name AS FieldName
FROM
    dbo.sysobjects 
    INNER JOIN dbo.syscolumns 
         ON dbo.sysobjects.id = dbo.syscolumns.id
WHERE
    dbo.sysobjects.name = 'MyTable'

【讨论】:

  • 您的答案如何适用于 Access/Jet?
  • 对不起,我收回我的-1,原来的问题在这一点上并不清楚。
  • 我想当这个答案发布时只有一个SQL标签,MS-Access标签是后来添加的。
【解决方案5】:

使用 DAO 自动化类。你的 Visual Studio 安装中可能已经有一个互操作库。如果没有,创建一个很容易;只需添加对 DAO COM 库的引用即可。

using dao;
...
DBEngineClass dbengine = new DBEngineClass();
dbengine.OpenDatabase(path, null, null, null);
Database database = dbengine.Workspaces[0].Databases[0];
List<string> fieldnames = new List<string>();
TableDef tdf = database.TableDefs[tableName];
for (int i = 0; i < tdf.Fields.Count; i++)
{
    fieldnames.Add(tdf.Fields[i].Name);
}
database.Close();
dbengine.Workspaces[0].Close();

这就像查询系统表(我发现在 Access 中存在问题)一样简单,并且您可以通过这种方式获得很多附加信息。

编辑: 我已经修改了我昨天发布的代码,我刚刚从 VB.NET 翻译了这些代码,并且缺少了几部分。我在VS2008中用C#重写并测试过。

【讨论】:

  • 从 C# 开始,ADO 目录功能可能会更简单。
  • IIRC 调用 OpenSchema 以获取 INFORMATION SCHEMA VIEW 对 C# 来说并不简单,而且对于列名来说可能不值得。
【解决方案6】:

此代码会将表的所有列名打印为具有所有列名的getter属性的类,然后可以在c#代码中使用

    declare @TableName sysname = '<EnterTableName>'
    declare @Result varchar(max) = 'public class ' + @TableName + '
    {'

    select @Result = @Result + '
        public static string ' + ColumnName + ' { get { return "'+ColumnName+'"; } }
    '
    from
    (
        select
            replace(col.name, ' ', '_') ColumnName,
            column_id ColumnId
        from sys.columns col
            join sys.types typ on
                col.system_type_id = typ.system_type_id AND col.user_type_id = typ.user_type_id
        where object_id = object_id(@TableName)
    ) t
    order by ColumnId

    set @Result = @Result  + '
    }'

    print @Result

输出:

 public class tblPracticeTestSections
 {
   public static string column1 { get { return "column1"; } }

   public static string column2{ get { return "column2"; } }

   public static string column3{ get { return "column3"; } }

   public static string column4{ get { return "column4"; } }

 }

【讨论】:

    【解决方案7】:

    根据您使用的数据库引擎,您可以轻松地查询数据库系统表以获取该信息

    对于访问,我在访问中找不到我认识你 can see the sys tables 的答案,从那里你可以尝试确定该信息在哪里,但我不确定如何执行此部分。尝试使用示例,但无处可去

    【讨论】:

    • MSysObjects 包含表格列表,遗憾的是没有对应的字段。
    【解决方案8】:

    对于 c# 中的 microsoft SQL,您可以执行以下操作:

    Dictionary<string, int> map = 
    (from DataRow row in Schema.Rows
     let columnName = (string)row["ColumnName"]
      select columnName)
     .Distinct(StringComparer.InvariantCulture)
     .Select((columnName, index) => new { Key = columnName, Value = index })
     .ToDictionary(pair => pair.Key, pair => pair.Value);
    

    因此在其索引中创建了一个列名映射,可以按如下方式使用:

    internal sealed class ColumnToIndexMap
    {
        private const string NameOfColumn = "ColumnName";
        private DataTable Schema { get; set; }
        private Dictionary<string, int> Map { get; set; }
    
        public ColumnToIndexMap(DataTable schema)
        {
            if (schema == null) throw new ArgumentNullException("schema");
            Schema = schema;
    
            Map = (from DataRow row in Schema.Rows
                   let columnName = (string)row[NameOfColumn]
                   select columnName)
                  .Distinct(StringComparer.InvariantCulture)
                  .Select((columnName, index) => new { Key = columnName, Value = index })
                  .ToDictionary(pair => pair.Key, pair => pair.Value);
        }
    
        int this[string name]
        {
            get { return Map[name]; }
        }
    
        string this[int index]
        {
            get { return Schema.Rows[index][NameOfColumn].ToString(); }
        }
    }
    

    【讨论】:

      【解决方案9】:

      我对 OleDb.Connection 的 GetSchema 属性很幸运:

      提供列数据的类。这将返回数据库中的所有列。然后可以通过列名过滤生成的 DataTable,这些列名(大部分)对应于标准 INFORMATION_SCHEMA(MS Access 不为我们提供)中的那些:

          class JetMetaData
          {
              /// <summary>
              /// Returns a datatable containing MetaData for all user-columns
              /// in the current JET Database. 
              /// </summary>
              /// <returns></returns>
              public static DataTable AllColumns(String ConnectionString)
              {
                  DataTable dt;
      
                  using (OleDbConnection cn = new OleDbConnection(ConnectionString))
                  {
                      cn.Open();
                      dt = cn.GetSchema("Columns");
                      cn.Close();
                  }
                  return dt;
              }
      
          }
      

      然后,在一个相当粗略且不那么优雅的示例中使用该类,并在 TABLE_NAME 上进行过滤:

          private void Form1_Load(object sender, EventArgs e)
          {
              DataTable dt = JetMetaData.AllColumns("", Properties.Settings.Default.JetConnection);
              String RowFilter = "TABLE_NAME = 'YourTableName'";
              DataView drv = dt.DefaultView;
              drv.RowFilter = RowFilter;
      
              DataGridView dgv = this.dataGridView1;
      
              dgv.DataSource = drv;
      
          }
      

      请注意,我并没有假装这都是经过完善的代码。这只是一个例子。但是我在很多场合都使用过这样的东西,实际上甚至创建了一个应用程序来使用类似的方法编写整个 MS Access 数据库(约束和所有)。

      虽然我在这个帖子中看到其他人提到了 get Schema,但似乎有些实现过于复杂。 . .

      希望有帮助!

      【讨论】:

        猜你喜欢
        • 2020-08-15
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        • 1970-01-01
        • 2011-09-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多