對DataTable進行分組


因為程序的特殊情景,需要在sql查出來的DataTable進行分組,DataTable分組可以使用linq,也可以自己寫分組程序。

linq相對簡單:

cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 300;
MySqlDataReader reader = cmd.ExecuteReader();

DataTable tb = new DataTable();
detailTable.Load(reader);
reader.Close();

var query = from c  in tb .AsEnumerable()
                        group c by new {
                            pingming = c.Field<string>("品名"),
                            guige = c.Field<string>("規格")
                                        }
                            into s
                            select new
                            {
                                pingming = s.Select(p => p.Field<string>("品名")).First(),
                                shuliang = s.Sum(p => Convert.ToInt32(p.Field<string>("數量"))),
                                guige = s.Select(p => p.Field<string>("規格")).First(),
                                biaohao = string.Join(";",s.Select(p => p.Field<string>("表號")))
                            };
      DataTable tbc = tb.Clone();
             query.ToList().ForEach(p =>tbc.Rows.Add(p.pingming, p.guige,p.biaohao,p.shuliang));//同下面foreach,只不過下面版本循環體可以做一些邏輯操作
      foreach(var row in query )
     {
        DataRow r = tbc.NewRow();
        r["pingming"]=row.pingming;
        r["guige "]=row.guige ;
        r["biaohao "]=row.biaohao;
        r["shuliang "]=row.shuliang ;
        tbc.Rows.Add(r);
     }
 注意:變量query只制定了LINQ查詢,該查詢不是通過這個賦值語句執行的,只要使用foreach循環訪問,該查詢就會執行。

 但是在linq中分組的字段是寫死的,而我的需求是選了哪些列對哪些列進行分組,這樣的話需要自己寫對DataTable 的分組。

dt 是分組前的DataTable,dt_result 是分組后的DataTable,strGroups是分組列以逗號隔開,numColumsStr是以#分割的匯總列

  dt_result=AddGroup(dt, strGroups, numColumsStr);

/// <summary>
/// 返回分組匯總后的datatable
/// </summary>
/// <param name="dt">要分組匯總的DataTable</param>
/// <param name="strGroupsField">分組列</param>
/// <param name="numColumsStr">需要求和的列,用#分割</param>
/// <returns></returns>
public DataTable AddGroup(DataTable dt, string strGroupFields, string numColumsStr)
{
if (dt.Rows.Count==0)
return dt;
DataTable table = TableSort(dt, strGroupFields);
DataTable result = dt.Clone();//結果
result.Columns["cinema_pay_type_name"].AllowDBNull = true;
result.Columns["consume_type"].AllowDBNull = true;
IList<string> numColumns = new List<string>();//存放匯總的數量或金額列
string[] columns = numColumsStr.Split('#');
foreach (string str in columns)
{
numColumns.Add(str);
}
string[] strGroupField = strGroupFields.Split(',');
string prevDept = "";//此組合列值
if (strGroupField.Length > 1)//按多個字段分組
{
for (int i = 0; i < strGroupField.Length; i++)
{
prevDept = prevDept + ","+table.Rows[0][strGroupField[i]].ToString();
}
prevDept = prevDept.Trim(',');
}
else if (strGroupFields != "" && strGroupField.Length == 1)//只按一列分組
{
prevDept = table.Rows[0][strGroupFields].ToString();//前一組的分組列值
}
else
{
return dt;
}
int NoOwn = 0;//同組項的第一行記錄的位置
int index = -1;//索引
foreach (DataRow item in table.Rows)
{
index++;//當前行索引
//如果相鄰兩行 分組字段相同 則繼續尋找下行,否則該行為同組的最后一行。進行數據處理
//currGroup == prevDept 表示為同組 則繼續比較下一行
string currGroup = GetGroupStr(table, item, strGroupFields);//此行分組字段組合,如 系統管理員,支付寶,票房
if (currGroup == prevDept && index != table.Rows.Count - 1)
{
continue;
}
else if (index == table.Rows.Count - 1)//到最后一行了
{
if (currGroup.ToString() != prevDept)//最后一行與上一行不是一組
{
//上一組結束,將此組行創建出來
DataRow row = CreateGroupRow(table, strGroupFields, numColumns, NoOwn, index - 1);//新建一組行
result.Rows.Add(row.ItemArray);
//最后一行是下一組
DataRow row2 = table.NewRow();
for (int i = 0; i < strGroupField.Length; i++)
{
row2[strGroupField[i]] = table.Rows[index][strGroupField[i]];
}
foreach (string columnName in numColumns)
{
if (columnName == "ratio_amount")
{
row2[columnName] = decimal.Parse(item[columnName].ToString() == "" ? "0" : item[columnName].ToString());
}
else
row2[columnName] = item[columnName];
}
result.Rows.Add(row2.ItemArray);
}
else//最后一行與上一行同組
{
DataRow row = CreateGroupRow(table, strGroupFields, numColumns, NoOwn, index);
result.Rows.Add(row.ItemArray);
}
}
else//與上一行不同
{
prevDept = GetGroupStr(table, item, strGroupFields);//當前分組標記,新的組開始查找
DataRow row = CreateGroupRow(table, strGroupFields,numColumns, NoOwn, index-1);
NoOwn = index;
result.Rows.Add(row.ItemArray);
}

}
return result;
}
/// <summary>
/// 將DataTable按分組列排序
/// </summary>
/// <param name="oldTable">排序前DataTable</param>
/// <param name="FieldName">分組字段</param>
/// <returns>排序后DataTable</returns>
public DataTable TableSort(DataTable oldTable, string FieldNames)
{
DataTable table = oldTable.Clone();//復制表結構
DataRow[] sortRows = oldTable.Select(null,FieldNames);
table = sortRows.CopyToDataTable();
//foreach(DataRow item in sortRows)
//{
// table.ImportRow(item);
//}
return table;
}
/// <summary>
/// 獲得DataTable中需要匯總的數字列
/// </summary>
/// <param name="table"></param>
/// <returns></returns>
private static IList<string> GetNumColumns(DataTable table)
{
IList<string> numColumns = new List<string>();//存放數字行
foreach (DataColumn column in table.Columns)
{
if (column.DataType == typeof(Decimal) || column.DataType == typeof(Int32) || column.DataType == typeof(Int64)
|| column.DataType == typeof(float) || column.DataType == typeof(Double))
{
numColumns.Add(column.ColumnName);
}
}
return numColumns;
}
/// <summary>
/// 返回這一組匯總行
/// </summary>
/// <param name="table">分組表</param>
/// <param name="numColumns">需要匯總的列</param>
/// <param name="startRowIndex">開始行</param>
/// <param name="endRowIndex">結束行</param>
/// <returns></returns>
private DataRow CreateGroupRow(DataTable table,string strGroupFields, IList<string> numColumns, int startRowIndex, int endRowIndex)
{
DataRow row = table.NewRow();//匯總行
//非匯總列取第一行值
string[] strGroupField = strGroupFields.Split(',');
for (int i = 0; i < strGroupField.Length; i++)
{
if (strGroupField[i] == "cinema_sell_date")
{
row[strGroupField[i]] = table.Rows[startRowIndex][strGroupField[i]];
}
else
{
row[strGroupField[i]] = table.Rows[startRowIndex][strGroupField[i]].ToString();
}

}
//從同組項的第一行記錄的位置 到 同組的最后一行

foreach (string columnName in numColumns)
{
object tempt = 0 ;
long suml=0;
decimal sumd = 0;
for (int i = startRowIndex; i < endRowIndex + 1; i++)
{
//object count = row[columnName];//匯總行 列值
tempt = table.Rows[i][columnName];//當前行 列值
//如果值為null 或 "" 則默認為 0
if (tempt == null || tempt.ToString().Trim() == "")
{
tempt = 0;
}
if (columnName == "sum_count" )
{
suml += Int64.Parse(tempt.ToString());//累加
}
else
sumd += decimal.Parse(tempt.ToString());//累加
}
if (columnName == "sum_count" || columnName == "ratio_amount")
{

row[columnName] = suml;
}
else
row[columnName] = sumd;

}
return row;
}
/// <summary>
/// 獲得此行分組字段的組合,以,隔開
/// </summary>
/// <param name="table"></param>
/// <param name="item"></param>
/// <param name="strGroupFields"></param>
/// <returns></returns>
private string GetGroupStr(DataTable table,DataRow item,string strGroupFields)
{
string[] strGroupField = strGroupFields.Split(',');
string currGroupStr = "";
for(int i = 0; i < strGroupField.Length; i++)
{
currGroupStr = currGroupStr + "," + item[strGroupField[i]].ToString();
}
currGroupStr = currGroupStr.Trim(',');
return currGroupStr;
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM