【问题标题】:How to remove empty rows from DataTable如何从 DataTable 中删除空行
【发布时间】:2011-10-24 18:53:42
【问题描述】:

我正在将数据从 Excel 工作表导入数据库。 Excel 工作表包含几个空行,我想删除这些空行,然后将清除的数据插入数据库。
我通过引用其他代码编写了一个代码,这是插入值的代码:

OleDbConnection cnn = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + txtExcelFile.Text + "';Extended Properties= 'Excel 8.0;HDR=Yes;IMEX=1'");
//DataTable dt = new DataTable();

try
{
    cnn.Open();
    OleDbDataAdapter data = new OleDbDataAdapter("select * from [Customers$]", cnn);
    data.Fill(dsExcel);
    dgvCustomers.ColumnHeadersVisible = false;

    SqlConnection connection = new SqlConnection("Data Source=COMPUTER-8EB749;Initial Catalog=KITS;Integrated Security=true");
    connection.Open();
    for (int i = 0; i < dsExcel.Tables[0].Rows.Count; i++)
    {
        string ID = ds.Tables[0].Rows[i][0].ToString();
        Int16 CustID = Convert.ToInt16(ID);
        string CustName = dsExcel.Tables[0].Rows[i][1].ToString();
        string CardScheme = dsExcel.Tables[0].Rows[i][2].ToString();
        string Outlet = dsExcel.Tables[0].Rows[i][3].ToString();
        string TerminalNum = dsExcel.Tables[0].Rows[i][4].ToString();
        Int32 Terminal = Convert.ToInt32(TerminalNum);
        string Date1 = dsExcel.Tables[0].Rows[i][5].ToString();
        DateTime Date = Convert.ToDateTime(Date1);
        string Time = dsExcel.Tables[0].Rows[i][6].ToString();
        DateTime DateTime = Convert.ToDateTime(Time);
        string Amount1 = ds.Tables[0].Rows[i][7].ToString();
        double Amount = Convert.ToDouble(Amount1);

        SqlCommand com = new SqlCommand("insert into Customer(CustID,CustName,CardScheme,Outlet,TerminalNum,TranDate,TranDateTime,Amount) values ('" + CustID + "','" + CustName + "','" + CardScheme + "','" + Outlet + "','" + Terminal + "','" + Date + "','" + DateTime + "','" + Amount + "')", connection);
        com.ExecuteNonQuery();
    }
    connection.Close();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}
finally
{
    MessageBox.Show("Data Inserted Successfully.");
}

谁能告诉我如何删除空行以便只插入数据?!

【问题讨论】:

  • 附带说明,您最好使用 using 块正确处理对象,例如using (OleDbConnection cnn = new OleDbConnection(...))

标签: c# excel datatable


【解决方案1】:

您的数据库本身有空行?这很奇怪。可能会在您执行选择查询时通过说主键列不为 NULL 来过滤它

【讨论】:

  • 嗯,据我所知,PK 字段不能为 NULL!
  • 我刚才说可以是PK领域。不是字面上的。在学生表中,名称列不能为空。所以不像 DB 风格那样完全是 PK
【解决方案2】:

为什么不在插入空行之前直接忽略它们?

if(string.IsNullOrEmpty(ID + CustName + CardScheme /*.. and so on */))
{
    continue;
}

像这样:

for (int i = 0; i < dsExcel.Tables[0].Rows.Count; i++)
{
    string ID = ds.Tables[0].Rows[i][0].ToString();
    Int16 CustID = Convert.ToInt16(ID);
    string CustName = dsExcel.Tables[0].Rows[i][1].ToString();
    string CardScheme = dsExcel.Tables[0].Rows[i][2].ToString();
    string Outlet = dsExcel.Tables[0].Rows[i][3].ToString();
    string TerminalNum = dsExcel.Tables[0].Rows[i][4].ToString();
    Int32 Terminal = Convert.ToInt32(TerminalNum);
    string Date1 = dsExcel.Tables[0].Rows[i][5].ToString();
    DateTime Date = Convert.ToDateTime(Date1);
    string Time = dsExcel.Tables[0].Rows[i][6].ToString();
    DateTime DateTime = Convert.ToDateTime(Time);
    string Amount1 = ds.Tables[0].Rows[i][7].ToString();
    double Amount = Convert.ToDouble(Amount1);

    /*** Add this if-statement to you code! ***/
    if(string.IsNullOrEmpty(ID + CustName + CardScheme + Outlet + TerminalNum + Date1 + Time + Amount1))
    {
        continue;
    }

    SqlCommand com = new SqlCommand("insert into Customer(CustID,CustName,CardScheme,Outlet,TerminalNum,TranDate,TranDateTime,Amount) values ('" + CustID + "','" + CustName + "','" + CardScheme + "','" + Outlet + "','" + Terminal + "','" + Date + "','" + DateTime + "','" + Amount + "')", connection);
    com.ExecuteNonQuery();
}

【讨论】:

  • 我可以知道您指示哪个部分继续.. 'if(string.IsNullOrEmpty(ID + CustName + CardScheme /*.. 等等 */)) { continue; }'
  • @Nazima 您的 for 循环,就在此语句之前:SqlCommand com = new SqlCommand("insert ...。这样你就不会插入空数据。
  • 我已经尝试过你所说的将 for 循环放入 if stmt..it 显示错误..
  • @Nazima 我已经更新了我的答案,以表明你应该在你的 for 循环中更新什么。
【解决方案3】:

试试这个。

public bool InsertRowsToDataBase()
{
    try
    {
        DataTable excelTable = new DataTable();

        string connString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + txtExcelFile.Text + "';Extended Properties= 'Excel 8.0;HDR=Yes;IMEX=1'";
        using (OleDbConnection cnn = new OleDbConnection(connString))
        {
            string query = "select * from [Customers$]";
            using (OleDbDataAdapter data = new OleDbDataAdapter(query, cnn))
            {
                data.Fill(excelTable);
            }
        }
        dgvCustomers.ColumnHeadersVisible = false;

        connString = "Data Source=COMPUTER-8EB749;Initial Catalog=KITS;Integrated Security=true";
        using (SqlConnection connection = new SqlConnection(connString))
        {
            connection.Open();
            for (int i = 0; i < excelTable.Rows.Length; i++)
            {
                //takes from the 3rd row
                if (i > 1)
                {
                    DataRow row = excelTable.Rows[i];
                    object ID = row[0];
                    if (ID != null && !String.IsNullOrEmpty(ID.ToString().Trim()))
                    {
                        Int16 CustID = Convert.ToInt16(ID);
                        string CustName = row[1].ToString();
                        string CardScheme = row[2].ToString();
                        string Outlet = row[3].ToString();
                        string TerminalNum = row[4].ToString();
                        Int32 Terminal = Convert.ToInt32(TerminalNum);
                        string Date1 = row[5].ToString();
                        DateTime Date = Convert.ToDateTime(Date1);
                        string Time = row[6].ToString();
                        DateTime DateTime = Convert.ToDateTime(Time);
                        string Amount1 = row[7].ToString();
                        double Amount = Convert.ToDouble(Amount1);

                        string columnNames = "CustID,CustName,CardScheme,Outlet,TerminalNum,TranDate,TranDateTime,Amount";
                        string query = String.Format("insert into Customer(0}) values ('{1}', '{2}','{3}','{4}','{5}','{6}','{7}','{8}')",
                            columnNames, CustID, CustName, CardScheme, Outlet, Terminal, Date, DateTime, Amount);
                        using (SqlCommand com = new SqlCommand(query, connection))
                        {
                            com.ExecuteNonQuery();
                        }
                    }
                }
                //this is your last row. do whatever you want with this
                DataRow lastRow = excelTable.Rows[excelTable.Rows.Count - 1];
            }
        }
        return true;
    }
    catch (Exception exception)
    {
        Elmah.ErrorSignal.FromCurrentContext().Raise(exception);
        return false;
    }
}

请注意,我只是检查 ID 是否为空,而不是插入任何这样的行,因为 ID 将是您表中的 PK。

【讨论】:

  • excel 表在第二行包含标题..当我尝试执行应用程序时,它显示错误“输入字符串格式不正确”..由于列名而发生此错误。 .我可以知道我怎么能先通过col名称然后是值..如果条件我必须改变..
  • 第一行是空的吗?你在哪里得到错误。哪一行?
  • 第一行包含子标题,即日期:将被删除..thts 工作正常..第二行包含列名,从第三行开始数据开始...我知道为什么会出现错误因为在第二行中,列名的类型是字符串而不是 int..这就是为什么它显示错误..错误显示在这一行中 Int16 CustID = Convert.ToInt16(ID);因为该行包含列名而不是值..所以我想知道如何通过第一个列名然后值..希望你理解
  • 谢谢你..它的工作..我需要更多的帮助..我是 .net 的新手,想改进编码..你能推荐任何书籍或网站或任何提示吗?编码技巧..如果你提出建议,我会很高兴。
  • 简而言之C#之类的书籍,如果您有中级知识,则深入了解C#。如果您刚开始,请先使用 C#。如果您有良好且便宜的互联网连接,请访问asp.net/general/videos。阅读 scott gu、jon skeet、dave ward、eric lippert 等的博客……一切顺利
【解决方案4】:
try
{
    OpenOleDBConnection();
    OleDbDataAdapter dataAdapter = new OleDbDataAdapter("select * from [" + SelectedSheet + "]", Connection);

    dataAdapter.Fill(DataTable);

    if ((DataTable != null) && (DataTable.Rows != null) && (DataTable.Rows.Count > 0))
    {
        List<System.Data.DataRow> removeRowIndex = new List<System.Data.DataRow>();
        int RowCounter = 0;
        foreach (System.Data.DataRow dRow in DataTable.Rows)
        {                            
            for(int index = 0; index < DataTable.Columns.Count; index++)
            {
                if (dRow[index] == DBNull.Value)  
                {
                    removeRowIndex.Add(dRow);
                    break;
                }
                else if (string.IsNullOrEmpty(dRow[index].ToString().Trim()))
                {
                    removeRowIndex.Add(dRow);
                    break;
                }
            }
            RowCounter++;
        }
        // Remove all blank of in-valid rows
        foreach (System.Data.DataRow rowIndex in removeRowIndex)
        {
            DataTable.Rows.Remove(rowIndex);
        }
    }
}
catch(Exception e)
{
    WPFMessageBox.Show(e.Message, Globalization.GetValue("Import_ImportOption_FormHeader"), WPFMessageBoxButtons.OK, WPFMessageBoxImage.Error);
}
finally
{
    CloseOleDBConnection();
}

如果它们在任何行中有空白条目,我也会跳过这些行。

【讨论】:

    【解决方案5】:

    这将删除每列不包含任何内容或空白的所有行:

    dataTable = dataTable.Rows
        .Cast<DataRow>()
        .Where(row => !row.ItemArray.All(field => field is DBNull || 
                                         string.IsNullOrWhiteSpace(field as string)))
        .CopyToDataTable();
    

    【讨论】:

    • 为什么有人(有某种意义)会连接到远程数据库服务器,遍历所有记录并删除空行?为什么不直接在数据库服务器上使用 TSQL 代码执行此操作(因为您显然对它有写访问权)?这显然是一行聪明的 LINQ 代码——但使用它并不是那么聪明。
    • @tEsTA - 您假设数据来自数据库。它可能来自 CSV、Excel 等。当您将数据从 Excel 提取到 DataTable 时,这对于清除多余/空行非常有用。 Excel 总是在工作表的末尾留下空行,你必须编写/运行一个宏来截​​断工作表 - 所以是的,这很有用!
    • @JoshM。你是对的 - 毕竟,这个 SO 问题是关于 Excel 电子表格的。但我会保留我的建议,因为它可以用于真正的数据库表(由一些不太了解的新手开发人员)。
    • 请注意,field as string 将作为值类型的null,因此我建议使用field as string ?? field.ToString() ;)。
    • 当只有标题而没有列数据时,我遇到了以下异常。 "源不包含 DataRows。"
    【解决方案6】:

    我已经制作了这个可以解决问题的私有方法。 它接受一个 DataTable 作为参数并返回相同的 DataTable 而没有空行。

    private DataTable StripEmptyRows(DataTable dt)
        {
            List<int> rowIndexesToBeDeleted = new List<int>();
            int indexCount = 0;
            foreach(var row in dt.Rows)
            {
                var r = (DataRow)row;
                int emptyCount = 0;
                int itemArrayCount = r.ItemArray.Length;
                foreach(var i in r.ItemArray) if(string.IsNullOrWhiteSpace (i.ToString())) emptyCount++;
    
                if(emptyCount == itemArrayCount) rowIndexesToBeDeleted.Add(indexCount);
    
                indexCount++;
            }
    
            int count = 0;
            foreach(var i in rowIndexesToBeDeleted)
            {
                dt.Rows.RemoveAt(i-count);
                count++;
            }
    
            return dt;
        }
    

    【讨论】:

    • 这只适用于我一半的空字符串行。我使用 IsNullOrWhiteSpace 而不是 IsNullOrEmpty,它适用于我的所有情况。
    【解决方案7】:
    public static DataTable RemoveEmptyRows(DataTable dt) 
    { 
        List removeRowIndex = new List(); 
    
        foreach (DataRow dRow in dt.Rows) 
        { 
            for (int index = 0; index < dt.Columns.Count; index++) 
            { 
                if (string.IsNullOrEmpty(dRow[index].ToString().Trim())) 
                { 
                    removeRowIndex.Add(dRow); 
                    break; 
                } 
                else if (dRow[index] == DBNull.Value) 
                { 
                    removeRowIndex.Add(dRow); 
                    break; 
                } 
            } 
        } 
    
        foreach (DataRow rowIndex in removeRowIndex) 
        { 
            dt.Rows.Remove(rowIndex); 
        } 
    
        return dt; 
    }
    

    【讨论】:

    【解决方案8】:

    检查空行

    Foreach(DataRow as row in datable.Rows) {
        var isEmpty = row.ItemArray.All(c => c is DBNull);
        if(!isEmpty) {
            //Your Logic
        }
    }
    

    【讨论】:

      【解决方案9】:

      这非常适合我:

      dt.Load(cmd.ExecuteReader());
      var x = dt.Rows.Cast<DataRow>()
         .Where(row => !Array.TrueForAll(row.ItemArray, value => 
         { return value.ToString().Length == 0; }
         ));
      
      dt = x.CopyToDataTable();
      

      【讨论】:

        【解决方案10】:

        我修改了 Cfrim 的答案。您需要检查空字符串和空白字符串。空白来自已删除的单元格,空白来自已删除的数据。

        private DataTable StripEmptyRows(DataTable dt)
                {
                    List<int> rowIndexesToBeDeleted = new List<int>();
                    int indexCount = 0;
                    foreach(var row in dt.Rows)
                    {
                        var r = (DataRow)row;
                        int emptyCount = 0;
                        int itemArrayCount = r.ItemArray.Length;
                            foreach (var i in dr.ItemArray)
                            {
                                if (string.IsNullOrEmpty(i.ToString()) || string.IsNullOrWhiteSpace(i.ToString()))
                                    emptyCount++;
                            }
        
                        if(emptyCount == itemArrayCount) rowIndexesToBeDeleted.Add(indexCount);
        
                        indexCount++;
                    }
        
                    int count = 0;
                    foreach(var i in rowIndexesToBeDeleted)
                    {
                        dt.Rows.RemoveAt(i-count);
                        count++;
                    }
        
                    return dt;
                }
        

        【讨论】:

          【解决方案11】:

          我在@Levitikon 帖子https://stackoverflow.com/a/9233696/5848472 中稍作改动 使用@shA.t 注释,此代码删除数据表中的所有空行和列:

          dt = ds.Tables[tablename].Rows
              .Cast<DataRow>()
              .Where(row => !row.ItemArray.All(field => field is DBNull || 
                     string.IsNullOrWhiteSpace(field as string ?? field.ToString())))
              .CopyToDataTable();
          foreach (var column in dt.Columns.Cast<DataColumn>().ToArray())
              {
                  if (dt.AsEnumerable().All(dr => dr.IsNull(column)))
                      dt.Columns.Remove(column);
              }
          

          【讨论】:

            【解决方案12】:

            这将从数据表中删除所有空行:

            DataTable dt = dt.Rows
                             .Cast<DataRow>()
                             .Where(row => !row.ItemArray.All(f => f is DBNull))
                             .CopyToDataTable();
            

            DataTable dt = dt.Rows
                             .Cast<DataRow>()
                             .Where(row => !row.ItemArray.All(f => f is DBNull || 
                                              string.IsNullOrEmpty(f as string ?? f.ToString())))
                             .CopyToDataTable();
            

            【讨论】:

              【解决方案13】:

              这对我有用。如果我们不检查行,直接做CopyToDataTable(),那么当数据表有空行时,你可能会得到一个异常。

              var rows = tbl.Rows.Cast<DataRow>()
                                          .Where(row => !row.ItemArray.All(field => field is DBNull || String.IsNullOrWhiteSpace(field as string ?? field.ToString())));
              
              if (rows.Any())
                  tbl = rows.CopyToDataTable();
              

              【讨论】:

                【解决方案14】:

                基于我使用的现有答案

                public static bool AllColumnsEmpty(this DataRow row)
                {
                    if (row == null)
                    {
                        return true;
                    }
                    else
                    {
                        foreach (var value in row.ItemArray)
                        {
                            if (value != null && value.ToString() != "")
                            {
                                return false;
                            }
                        }
                        return true;
                    }
                }
                
                public static void RemoveEmptyRows(this DataTable data)
                {
                    var rowsToDelete = data.Rows.Cast<DataRow>()
                        .Where(row => row.AllColumnsEmpty())
                        .ToList();
                
                    rowsToDelete.ForEach(row => data.Rows.Remove(row));
                }
                

                然后使用

                someDatatable.RemoveEmptyRows();
                

                【讨论】:

                  【解决方案15】:
                  for (int i = dt.Rows.Count - 1; i >= 0; i--) {
                      if (dt.Rows[i][1] == DBNull.Value) {
                          dt.Rows[i].Delete();
                      }
                  }
                  dt.AcceptChanges();
                  return dt;
                  

                  【讨论】:

                  • 你能edit你的答案解释为什么你的帖子与其他14个答案不同吗?为什么它解决了这个问题?
                  • 虽然此代码可能会回答问题,但提供有关 why 和/或 如何 此代码回答问题的附加上下文可提高其长期价值.
                  • 没有函数定义时为什么要return
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-06-13
                  • 2013-09-22
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-04-08
                  相关资源
                  最近更新 更多