【问题标题】:C# xls & xlsx query selecting from a sheet regardless of sheet nameC# xls 和 xlsx 查询从工作表中选择,而不考虑工作表名称
【发布时间】:2019-06-28 07:03:53
【问题描述】:

这是我的GetData 方法:

    private DataTable GetData(string userFileName)
    {
        string dirName = Path.GetDirectoryName(userFileName);
        string fileName = Path.GetFileName(userFileName);
        string fileExtension = Path.GetExtension(userFileName);
        string connection = string.Empty;
        string query = string.Empty;

        switch (fileExtension)
        {
            case ".xls":
                connection = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={userFileName};" +
                               "Extended Properties=\"Excel 8.0; HDR=Yes; IMEX=1\"";
                query = "SELECT * FROM [Sheet1$]";
                break;

            case ".xlsx":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={userFileName};" +
                               "Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=1\"";
                query = "SELECT * FROM [Sheet1$]";
                break;

            case ".csv":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dirName};" +
                               "Extended Properties=\"text; HDR=Yes; IMEX=1; FMT=Delimited\"";
                query = $"SELECT * FROM [{fileName}]";
                break;
        }

        return FillData(connection, query);
    }

它适用于.csv 文件,因为它使用文件名而不是工作表名。

它适用于具有名为 Sheet1 的工作表的 .xls.xlsx 文件。

当我尝试使用具有不同工作表名称的 .xls/.xlsx 文件时,我收到以下错误:

System.Data.OleDb.OleDbException:“Sheet1$”不是有效名称。确保它不包含无效字符或标点符号,并且不要太长。'

另一个问题的答案:

using (OleDbConnection conn = new OleDbConnection(connString))
{
    conn.Open();
    dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
    Sheet1= dtSchema.Rows[0].Field<string>("TABLE_NAME");
}

没有帮助,因为我不知道这应该放在我的代码中的什么位置,也没有任何迹象表明应该放在哪里。

我是这样添加的吗?

string Sheet1 = dataGridView1.Rows[0].Field<string>("TABLE_NAME");

这给了我一个错误:

错误 CS1929“DataGridViewRow”不包含“Field”的定义,并且最佳扩展方法重载“DataRowExtensions.Field(DataRow, string)”需要“DataRow”类型的接收器

【问题讨论】:

  • @woldemar 该链接没有为我提供解决问题所需的解释。
  • @Matt string Sheet1 = **dataGridView1**....... wtf 你在做什么? :) 答案中没有任何网格视图。我认为您正在使用FillData 方法打开连接,打开您的连接并在其上调用var dtSchema = conn.GetOleDbSchemaTable
  • 只是添加@woldemar 已经写了大部分想法...重复的答案只是指出您需要获取表架构并且列名“TABLE_NAME”的第一行将包含 Excel Sheet1名称,您可以在查询中使用。

标签: c# excel winforms datatable openfiledialog


【解决方案1】:

我很快为您的代码添加了一些修复程序,但这个解决方案还远远不够完善。 您应该考虑来自@woldemar 的解决方案,并更深入地理解代码。一些优秀的资源可以在这里找到:https://github.com/EbookFoundation/free-programming-books

回到您的代码。要找出第一个工作表的名称,您必须首先打开与 xlsx 文件的连接。然后使用示例中的一些代码查询元数据:

using (OleDbConnection conn = new OleDbConnection(connString))
{
    conn.Open();
    dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
    Sheet1= dtSchema.Rows[0].Field<string>("TABLE_NAME");
}

之后,您可以将收到的工作表名称插入到您的查询中。

又快又脏,你的代码应该看起来像这样才能使用 xlsx 文件:

private static DataTable GetData(string userFileName)
    {
        string dirName = Path.GetDirectoryName(userFileName);
        string fileName = Path.GetFileName(userFileName);
        string fileExtension = Path.GetExtension(userFileName);
        string connection = string.Empty;
        string query = string.Empty;

        switch (fileExtension)
        {
            case ".xls":
                connection = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={userFileName};" +
                             "Extended Properties=\"Excel 8.0; HDR=Yes; IMEX=1\"";
                query = "SELECT * FROM [Sheet1$]";
                break;

            case ".xlsx":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={userFileName};" +
                             "Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=1\"";
                string sheetName;
                using (OleDbConnection con = new OleDbConnection(connection))
                {
                    con.Open();
                    var dtSchema = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
                    sheetName = dtSchema.Rows[0].Field<string>("TABLE_NAME");
                }

                if (sheetName.Length <= 0) throw new InvalidDataException("No sheet found."); // abort if no sheet name was returned

                query = $"SELECT * FROM [{sheetName}]";
                break;

            case ".csv":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dirName};" +
                             "Extended Properties=\"text; HDR=Yes; IMEX=1; FMT=Delimited\"";
                query = $"SELECT * FROM [{fileName}]";
                break;
        }

        return FillData(connection, query);
    }

【讨论】:

  • 完美工作:)
  • :D @woldemar 欢迎来到 SO。至少这个答案是一口气发布的。当 SO 专家用一句话/一行代码发布答案然后开始将其编辑为完全可接受的答案时,存在“技巧”。如果您像普通人一样写下完全可以接受的答案然后发布,但是您的答案很晚,所以专家将被接受:)
  • 并非所有人都能从专业人士开始。他无法使用给定的提示,所以我认为向他展示如何在他的代码中使用它们将比告诉他他的代码有多愚蠢更能帮助他。我想我已经明确表示他必须更深入地研究编程理论。我们没有人有时间从基础开始详细地向他解释如何编写“完美”代码。
  • @woldemar 问题和后续修复几乎不是开创性的,也不是大量的代码,如果有更有效的方法,那就太好了,但对于这种情况,只需要引入 excel 工作表就可以了工作表名称,它是一个有效且有用的解决方案。
【解决方案2】:

尝试在 GetData 方法的末尾调用此方法而不是 FillData 方法,正如您所见,不需要传递 query,因为此方法从文档架构中获取 sheetname self。

    private DataTable GetDataFromFirstSheet(string connection)
    {
        using (OleDbConnection conn = new OleDbConnection(connection))
        {
            using (DataTable dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" }))
            {
                string firstSheet = dtSchema.Rows[0].Field<string>("TABLE_NAME");

                //try to remove $ from sheetname if it will be not working
                using (OleDbCommand cmd = new OleDbCommand($"SELECT * FROM [{firstSheet}$]", conn))
                {
                    using (OleDbDataAdapter adp = new OleDbDataAdapter(cmd))
                    {
                        conn.Open();

                        DataTable dt = new DataTable();
                        adp.Fill(dt);

                        return dt;
                    }                            
                }
            }
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    相关资源
    最近更新 更多