我目前有一个DataTable
,其中包含以下列:日期,X1,Y1,Z1,X2,Y2,Z2 ...... Xn,Yn,Zn。
填充时,Date ALWAYS有一个值,X / Y / Z1到X / Y / Zn可以是DBNull
,string
或int
。如果除了Date之外的整行是DBNull,我想删除该特定行。
我目前正在进行详尽的搜索,使用for循环遍历每一行,然后使用嵌套的for循环,检查每个单元格,如果我找不到任何数据(即只有dbnull的),则调用RemoveAt ,并将外循环重置为从零开始。
是否有更好/更少的hacky方式执行此操作?无法修改数据表的初始构建,这必须是构建后发生的事情。
答案 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);
}