[.NET]將DataTable中各2筆資料中去除DBNull然後合併

[.NET]將DataTable中各2筆資料中去除DBNull然後合併

在論談上有看到「ADO.NET DATA TABLE」覺得蠻有趣的,所以就記錄下來。

主要DataTable中有ID, NAME, SURNAME等欄位,各筆資料中NAME或SURNAME有一個欄位是DBNull,然後希望可以將各2筆資料合併非DBNull的欄位,如下,

ID NAME SURNAME
1 DBNull MIKE
1 JON DBNull
2 DBNull Berry
2 SON DBNull

 

合併之後如下,

ID NAME SURNAME
1 JON MIKE
2 SON Berry

 

Way1:VijayPatel 大大的作法是先將資料轉成ToList,然後再Group起來,如下,


DataTable dt = new DataTable("test");
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("NAME", typeof(string));
dt.Columns.Add("SURNAME", typeof(string));
dt.Rows.Add(1, DBNull.Value, "MIKE");
dt.Rows.Add(1, "JON", DBNull.Value);
dt.Rows.Add(2, DBNull.Value, "Berry");
dt.Rows.Add(2, "SON", DBNull.Value);
//先轉成List
var collection = dt.AsEnumerable()
    .Select(x => new
    {
        ID = x["ID"],
        Name = x["NAME"],
        SURNAME = x["SURNAME"]
    }).ToList();
//然後再Group
var newCollection = collection.GroupBy(x => x.ID).Select(x => new
{
    ID = x.Key,
    Name = x.First(y => !string.IsNullOrWhiteSpace(y.Name.ToString())).Name.ToString(),
    SURNAME = x.First(y => !string.IsNullOrWhiteSpace(y.SURNAME.ToString())).SURNAME.ToString()
}).ToList();

 

Way2:以類似SubQuery的方式來找出有值的欄位,然後再Distinct,如下,


DataTable dt = new DataTable("test");
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("NAME", typeof(string));
dt.Columns.Add("SURNAME", typeof(string));
dt.Rows.Add(1, DBNull.Value, "MIKE");
dt.Rows.Add(1, "JON", DBNull.Value);
dt.Rows.Add(2, DBNull.Value, "Berry");
dt.Rows.Add(2, "SON", DBNull.Value);
//SubQuery的方式來找出有值的欄位,然後再Distinct
var collection3 = dt.AsEnumerable()
                .Select(x => new
                {
                    ID = x["ID"],
                    Name = dt.AsEnumerable()
                    .Where(y =>!string.IsNullOrWhiteSpace(y["NAME"].ToString()) && x["ID"].ToString() == y["ID"].ToString() )
                    .Select(y => y["NAME"]).FirstOrDefault(),
                    SURNAME = dt.AsEnumerable()
                    .Where(y =>!string.IsNullOrWhiteSpace(y["SURNAME"].ToString()) && x["ID"].ToString() == y["ID"].ToString())
                    .Select(y => y["SURNAME"]).FirstOrDefault(),
                }).Distinct().ToList();

 

Way3:以Self Join方式,過濾Null之後再Distinct,如下,


DataTable dt = new DataTable("test");
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("NAME", typeof(string));
dt.Columns.Add("SURNAME", typeof(string));

dt.Rows.Add(1, DBNull.Value, "MIKE");
dt.Rows.Add(1, "JON", DBNull.Value);
dt.Rows.Add(2, DBNull.Value, "Berry");
dt.Rows.Add(2, "SON", DBNull.Value);

//Self Join,過濾非Null之後再Distinct
var collection4 =
	(from row1 in dt.AsEnumerable()
	join row2 in dt.AsEnumerable()
		on row1["ID"] equals row2["ID"]
	select new
		{
			ID = row1["ID"] ,
			NAME = row1.IsNull("NAME") ? row2["NAME"] : row1["NAME"],
			SURNAME = row1.IsNull("SURNAME") ? row2["SURNAME"] : row1["SURNAME"]
		}).Where(x => !string.IsNullOrEmpty(x.NAME.ToString()) && !string.IsNullOrEmpty(x.SURNAME.ToString()))
		.Distinct();

 

Way4:簡化 VijayPatel 大大,以Group並依First中的Filter去取出第1個有值的資料,如下,


DataTable dt = new DataTable("test");
dt.Columns.Add("ID", typeof(int));
dt.Columns.Add("NAME", typeof(string));
dt.Columns.Add("SURNAME", typeof(string));

dt.Rows.Add(1, DBNull.Value, "MIKE");
dt.Rows.Add(1, "JON", DBNull.Value);
dt.Rows.Add(2, DBNull.Value, "Berry");
dt.Rows.Add(2, "SON", DBNull.Value);

//以Group並依First中的Filter去取出第1個有值的資料
var collection5 =
	from row in dt.AsEnumerable()
	group row by row["ID"]
	into g
	select new
		{
			ID = g.Key,
			NAME = g.First(y => !y.IsNull("NAME"))["NAME"],
			SURNAME = g.First(y => !y.IsNull("SURNAME"))["SURNAME"]
		};

 

 

不知大家是否有其他的方式呢?

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^