2013-09-25 21 views
0

我目前有DataTable與以下列:日期,X1,Y1,Z1,X2,Y2,Z2 ... Xn,Yn,Zn。更好的方法來過濾數據表

當填充時,日期總是有值,並且X/Y/Z1到X/Y/Zn可以是DBNullstringint。如果整個行除了日期,是DBNull,我想刪除該特定的行。

我目前正在做一個詳盡的搜索,循環遍歷每一行for循環,然後用嵌套for循環,檢查每個單元格,如果我沒有找到任何數據(即只有dbnull的),然後我打電話RemoveAt,然後重置外部循環以再次從零開始。

執行此操作有更好/更簡單的方法嗎?數據表的初始構建不能修改,這必須是構建後發生的事情。

+0

可他們也可空''或者如果'string'是什麼'null'(而不是'DBNull.Value')? –

+0

你不需要從零開始,你只需要在RemoveAt之後搜索相同的Rowindex,因爲它騎起來 – WiiMaxx

回答

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:只需要有效的行做出新DataTable的建議我@Tim在評論時,你有很多無效的,以提高性能行

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

我想刪除除第一列之外的所有列,具有dbnull.value的值。 – bizzehdee

+0

@bizzehdee更新了我的答案,'跳過(1)'忽略第一列 –

+0

而不是採取所有無效的行,從他們創建一個數組和循環,從表中刪除它們,會不會更好條款的可讀性和效率)[只採取有效的行並直接使用'CopyToDataTable]](http://stackoverflow.com/a/19004092/284240)? –

0

可能這會幫助你。試試這個

​​

你也可以爲其他列做同樣的事情。

爲什麼不檢查查詢中的空值。檢查ISNULL(columnName, value)作爲ColumnName。查看更多詳細信息here

+0

DateTime不能爲空:) –

+0

@lazyberezovsky答案更新 – nrsharma

0

注意:TH ESE現在我的例子>>不EXCATLLY爲表格>>>所以更改爲自己 的主要幫助是這裏>>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(); 
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

0

修改答案:

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

我檢查,它的工作原理。

EDIT

響應於@Tim Schmelter評論:

1。你需要在C#中的myDataTable.AsEnumerable()

如果你有一個強類型的DataTable,你不需要。我認爲是這樣,因爲OP說:

datatable的初始建築不能修改,這必須是 發生後建設的東西。

也許我我以前不明白他的意思(我的英語有時會失敗我)

2。算上非空字段不正確,因爲字符串可以爲空 這是不一樣的,如果它是DBNull.Value(也可根據OP的 規格)

你可能是正確的。如果OP說他只想要DBNull,應該刪除第二個條件(這是我的一個壞習慣,以防萬一)檢查空值

3。 ToList創建另一個多餘的列表

是的。如果沒有ToList(),則不能使用ForEach()。老式的foreach可以用來替代,或者用於循環(因爲foreach不喜歡當你嘗試修改裏面的集合)。你仍然需要以某種方式保持你的結果。

4。 DataRow.Delete它不從表中刪除什麼是所需的,但它標記爲DataAdapter刪除(OP的沒有提及 ,他使用一個,它也不是所需的)。

謝謝你指出。

+0

這有幾個問題:1.您需要'在myCodeData.AsEnumerable()'在C#2.計數非空字段是不正確的,因爲一個字符串可以爲空,這是不一樣的,如果它是'DBNull.Value'(也根據OP的規範)3.'ToList'創建另一個'List',它是多餘的4.'DataRow.Delete'不會從表中刪除所需的內容,但會將其標記爲已刪除'DataAdapter'(OP的沒有提到他使用了一個,這也是不希望的)。 –

+0

@Tim Schmelter我編輯了我的答案 – Arie

+0

我已經刪除了我的downvote的努力。然而,批評的點仍然存在。 'DataTable'也可以是不受OP控制的,因爲他(他的method/class/dll)只是消費者,所以沒有任何指示強類型的DataTable。使用'Count'而不是'Any'(或'All')不利於另一個原因:它需要檢查一個序列的所有項目(可能是一個耗時的大量查詢)以獲得計數,即使你只是想要知道有一個。 'ToList' +'ForEach'是我經常看到的一個壞習慣。你也可以使用一個便宜的'foreach'來調用'Delete'。 –

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()(我不知道,但我假定這是因爲數據表是.NET的強大的數據結構來處理表格數據)

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); 
     } 
+0

列是動態的,所以我不能靜態列出代碼中的每一列。因此X/Y/Z1到X/Y/Zn – bizzehdee

相關問題