C# 使用Oledb筛选excel电子表格并返回特定值

C# 使用Oledb筛选excel电子表格并返回特定值,c#,excel,oledb,oledbconnection,C#,Excel,Oledb,Oledbconnection,我有一个WPF应用程序,我想根据两个变量从中提取特定数据。 数据源是下面的电子表格,没有应用任何特定设置,它只是原始数据 我想要一种我可以称之为的方法,即: GetValue("A", "Dec-19") 与: 这将返回值0。 我尝试了许多方法,但无法产生任何功能。 这是我的一个尝试的一个变体,我正在工作 public double GetValue(string type, OleDbConnection TargetBuildOleDbConnection, DateTime Selec

我有一个WPF应用程序,我想根据两个变量从中提取特定数据。 数据源是下面的电子表格,没有应用任何特定设置,它只是原始数据

我想要一种我可以称之为的方法,即:

GetValue("A", "Dec-19")
与:

这将返回值0。 我尝试了许多方法,但无法产生任何功能。 这是我的一个尝试的一个变体,我正在工作

public double GetValue(string type, OleDbConnection TargetBuildOleDbConnection, DateTime Selection)
{
    string date = Selection.ToString("MMM-yy", ci);
    string CustomQuery = "SELECT ['" + date + "'] FROM [SHEET1$A1:Z1] WHERE [Product] = '" + type + "'";
    using (DataTable dt = new DataTable())
    {
        using (DataView dv = new DataView(dt))
        {
            using (OleDbCommand comm = new OleDbCommand())
            {
                comm.CommandText = "Select * from [Build Schedule$]";
                comm.Connection = TargetBuildOleDbConnection;
                using (OleDbDataAdapter da = new OleDbDataAdapter())
                {
                    da.SelectCommand = comm;
                    da.Fill(dt);

                }
            }
            dv.RowFilter = "SELECT ['" + date + "'] FROM [SHEET1$A1:Z1]"; //throwing exception
            double target = dt.Rows[0].Field<int>(0);
            return target;
        }
    }
}

这是您的原始代码的修改版本,有望实现您所期望的:

public double GetValue(string product, OleDbConnection targetBuildOleDbConnection, DateTime dte)
{
    const double defaultValue = 0; // Value to return if no match is found

    const string prodParamName = "@prod";

    using (OleDbCommand comm = new OleDbCommand())
    {
        comm.Connection = targetBuildOleDbConnection;
        comm.CommandText = string.Format("SELECT * FROM [Build Schedule$] WHERE Product={0}", prodParamName);
        comm.Parameters.Add(prodParamName, OleDbType.VarWChar); // Maybe VarChar is good enough (?)
        comm.Parameters[prodParamName].Value = product;

        using (OleDbDataReader rdr = comm.ExecuteReader())
        {
            if (!rdr.Read()) return defaultValue;

            for (var i = 1; i < rdr.FieldCount; i++)
            {
                var colName = rdr.GetName(i);

                double colNumber;
                if (double.TryParse(colName, out colNumber)) // If the date headers have actual Excel dates
                {
                    DateTime colDate = DateTime.FromOADate(colNumber); // Convert Excel's date number to a C# date
                    if (colDate.Month != dte.Month || colDate.Year != dte.Year) continue;
                }
                else if (colName != dte.ToString("MMM-yy")) // If the date headers are actual Excel strings
                    continue;

                double colValue;
                if (double.TryParse(rdr.GetValue(i).ToString(), out colValue)) return colValue;

                break; // No point in continuing, since we found the right column, but it did not have a valid double
            }
        }

        return  defaultValue;
    }
}
请注意以下事项:

代码假定数据位于名为Build Schedule的工作表上 代码没有使用您在ToString调用中使用的ci CultureInfo变量,因为我不知道该变量来自何处 由于函数是double类型,如果没有找到匹配值,则返回0而不是null;如果您在这些情况下更喜欢null,则可以将函数更改为double?类型,但调用此函数的代码必须知道可以返回null 无论日期标题单元格(如11月19日和12月19日单元格)是否包含仅在Excel中格式化为MMM yy的日期值,或者是否包含实际字符串,代码理论上都应有效;如果只想处理一种情况,则可能需要消除for循环中的if或else块 如果您使用的是旧版本的C,那么代码不会利用最新版本C中的某些语法改进 可以优化对右列的搜索,尤其是在连续多次调用此函数的情况下
我测试了这段代码,它似乎每次都返回正确的值。我希望它对您有用。

好吧,至少提供您检索数据失败的代码。否则,我们需要为您编写所有来自Scratch抱歉的代码!现在添加了一些东西为什么不直接使用CustomQuery,而不是检索整个表,然后尝试对其进行筛选?无论如何,RowFilter的语法不正确。它应该是一个WHERE表达式,没有单词wherend,使用的连接字符串是什么?什么是正确的图纸名称Build Schedule$或Sheet1$?看起来应该可以-我将在接下来的几天内进行测试,谢谢!非常感谢-经过一些调整后,它工作得非常好,可以与我的代码一起使用。太棒了!很高兴知道!:
public double GetValue(string product, OleDbConnection targetBuildOleDbConnection, DateTime dte)
{
    const double defaultValue = 0; // Value to return if no match is found

    const string prodParamName = "@prod";

    using (OleDbCommand comm = new OleDbCommand())
    {
        comm.Connection = targetBuildOleDbConnection;
        comm.CommandText = string.Format("SELECT * FROM [Build Schedule$] WHERE Product={0}", prodParamName);
        comm.Parameters.Add(prodParamName, OleDbType.VarWChar); // Maybe VarChar is good enough (?)
        comm.Parameters[prodParamName].Value = product;

        using (OleDbDataReader rdr = comm.ExecuteReader())
        {
            if (!rdr.Read()) return defaultValue;

            for (var i = 1; i < rdr.FieldCount; i++)
            {
                var colName = rdr.GetName(i);

                double colNumber;
                if (double.TryParse(colName, out colNumber)) // If the date headers have actual Excel dates
                {
                    DateTime colDate = DateTime.FromOADate(colNumber); // Convert Excel's date number to a C# date
                    if (colDate.Month != dte.Month || colDate.Year != dte.Year) continue;
                }
                else if (colName != dte.ToString("MMM-yy")) // If the date headers are actual Excel strings
                    continue;

                double colValue;
                if (double.TryParse(rdr.GetValue(i).ToString(), out colValue)) return colValue;

                break; // No point in continuing, since we found the right column, but it did not have a valid double
            }
        }

        return  defaultValue;
    }
}