过滤DataTable的更好方法

时间:2013-09-25 11:31:08

标签: c# datatable

我目前有一个DataTable,其中包含以下列:日期,X1,Y1,Z1,X2,Y2,Z2 ...... Xn,Yn,Zn。

填充时,Date ALWAYS有一个值,X / Y / Z1到X / Y / Zn可以是DBNullstringint。如果除了Date之外的整行是DBNull,我想删除该特定行。

我目前正在进行详尽的搜索,使用for循环遍历每一行,然后使用嵌套的for循环,检查每个单元格,如果我找不到任何数据(即只有dbnull的),则调用RemoveAt ,并将外循环重置为从零开始。

是否有更好/更少的hacky方式执行此操作?无法修改数据表的初始构建,这必须是构建后发生的事情。

7 个答案:

答案 0 :(得分:6)

如果我理解正确,如果所有列都有DbNull.Value,则要删除一行。 请尝试以下操作。

DataTable table = new DataTable();
string[] columns = table.Columns.Cast<DataColumn>()
                                .Select(x => x.ColumnName)
                                .Skip(1)//skip to ignore first column
                                .ToArray();

<强>方法一: 删除所有无效行

var invalidRows = table.AsEnumerable()
    .Where(x => columns.All(c => x.Field<object>(c) == DBNull.Value))
    .ToArray();

foreach (var row in invalidRows)
{
    table.Rows.Remove(row);
}

方法2:只获取有效行,并根据建议我的@Tim创建新的DataTable,以便在有许多无效行时提高性能

var newTable = table.AsEnumerable()
             .Where(x => columns.Any(c => x.Field<object>(c) != DBNull.Value))
             .CopyToDataTable();

答案 1 :(得分:0)

可能这会对你有所帮助。试试这个

    var ordered = yourdatatable.AsEnumerable().Where(x => x.Field<DateTime>("ColumnName") != null);

if (ordered.Count() > 0)
                        {
                            yourdatatable= orderedCopyToDataTable();
                        }

您也可以对其他列执行相同的操作。

或者

为什么不检查查询中的空值。检查ISNULL(columnName, value)作为ColumnName。查看更多详情here

答案 2 :(得分:0)

注意:这些是我的例子&gt;&gt;不是你的表格&gt;&gt;&gt;因此改变自己的自我 主要帮助在这里&gt;&gt; Help

然后  方式一:

dtData.Select("ID=1 AND ID2=3");

方式二:

GridFieldDAO dao = new GridFieldDAO();
    //Load My DataTable
    DataTable dt = dao.getDT();
    //Get My rows based off selection criteria
    DataRow[] drs = dt.Select("(detailID = 1) AND (detailTypeID = 2)");
    //make a new "results" datatable via clone to keep structure
    DataTable dt2 = dt.Clone();
    //Import the Rows
    foreach (DataRow d in drs)
    {
        dt2.ImportRow(d);
    }
    //Bind to my new DataTable and it will only show rows based off selection 
    //criteria
    myGrid.DataSource = dt2;
    myGrid.DataBind();

最好的方法是:

DataTable tblFiltered = table.AsEnumerable()
      .Where(row => row.Field<String>("Nachname") == username
               &&   row.Field<String>("Ort") == location)
      .OrderByDescending(row => row.Field<String>("Nachname"))
      .CopyToDataTable();

答案 3 :(得分:0)

您可以使用这个小Linq查询:

var columnsWithoutDate = table.Columns.Cast<DataColumn>().Skip(1);
table = table.AsEnumerable()
    .Where(row => columnsWithoutDate.Any(col => !row.IsNull(col)))
    .CopyToDataTable();

Skip(1)会返回除第一列之外的所有列,因此会排除您的日期列。 Where枚举表中的所有DataRows并获取至少一个非空字段的所有行(请参阅:DataRow.IsNull(column))。最后CopyToDataTable创建一个新的DataTable

答案 4 :(得分:0)

修改后的答案:

myDataTable.AsEnumerable().Where(a => a.ItemArray.Count(b=>b != DBNull.Value)==1).ToList().ForEach(row => dataTable.Rows.Remove(row));

我查了一下,确实有效。

修改

回应@Tim Schmelter评论:

  

1。你需要C#

中的myDataTable.AsEnumerable()

如果你有一个强类型的DataTable,你就没有。我认为是这样的,因为OP说:

  

无法修改数据表的初始构建,这必须是   建筑后发生的事情。

也许我不明白他的意思(我的英语有时会让我失望)

  

2。 count非空字段是不正确的,因为字符串可以为null   这与DBNull.Value不同(也是根据OP的   规格)

你可能是对的。如果OP说他只想要DBNull,那么应该删除第二个条件(为了以防万一,检查null是一个坏习惯)

  

3。 ToList创建另一个冗余的List

是。如果没有ToList(),则不能使用ForEach()。可以使用旧式foreach,或者循环使用(因为foreach不喜欢当你尝试修改其中的集合时)。你仍然必须以某种方式保持你的结果。

  

4。 DataRow.Delete不会从表中删除所需的内容,   但它将其标记为已删除的DataAdapter(OP尚未提及   他正在使用一个,这也是不可取的。)

感谢您指出这一点。

答案 5 :(得分:0)

您是否尝试过使用DataTable的RowFilter?

DataTable dt = GetData();
//set the filter
dt.DefaultView.RowFilter = "----your filter----";
//then access the DataView
foreach (DataRowView drv in dt.DefaultView)
{
            //you can also get a row from rowview
            DataRow dr = drv.Row;
}

查看此文档,它们还解释了如何处理过滤器中的空值。

http://msdn.microsoft.com/en-us/library/system.data.dataview.rowfilter.aspx

你也可以使用相同过滤器的Select()方法,参考下面的答案,两种方法都有一个很好的比较。

DataView.RowFilter Vs DataTable.Select() vs DataTable.Rows.Find()

我不建议使用 AsEnumerable()方法,虽然看起来像简单的代码,但它就像在行上执行foreach循环并具有IF条件。

DataTable过滤器方法应该比 AsEnumerable()更快(我不确定,但我假设这是因为DataTable是.net强大的数据结构来处理表格数据)

答案 6 :(得分:0)

我会选择这样的事情:

        var test = from row in table.AsEnumerable()
                   where (!row.IsNull("col1") || !row.IsNull("col2"))
                   select row;

        //option1
        DataTable dt = test.CopyToDataTable<DataRow>();

        //option2
        DataTable dt2 = new DataTable();
        dt2.Columns.Add("col1", typeof(String));
        dt2.Columns.Add("col2", typeof(Int32));

        foreach (var v in test)
        {
            DataRow dr = dt2.NewRow();
            dr["col1"] = v.Field<String>("col1");
            dr["col1"] = v.Field<Int32>("col2");
            dt2.Rows.Add(dr);
        }