将下面表(1)格式的数据转换为表(2)格式的数据。很明显,这是一个行转列的要求,本想在数据库中行转列,因为在数据库中行转列是比较简单的,方法可以参考本站SQLServer中(行列转换)行转列及列转行且加平均值及汇总值,但因其它需求,最终需将该转化搬到C#中进行了。
(表1)
表(2)
不多说了,下面开始在DataTable行转列示例:
//DataTable行转列
private DataTable RCC(DataTable _outDataSource)
{
//从DataTable中读取不重复的日期行,用来构造新DataTable的列
DataTable distinct_date = _outDataSource.DefaultView.ToTable(true, "日期");
DataTable new_DataTable = new DataTable();
//将客户名称列添加到新表中
DataColumn new_d_col = new DataColumn();
new_d_col.ColumnName = "客户名称";
new_d_col.Caption = "";
new_DataTable.Columns.Add(new_d_col);
StringBuilder str_sum = new StringBuilder();
//开始在新表中构造日期列
foreach (DataRow dr in distinct_date.Rows)
{
new_d_col = new DataColumn();
new_d_col.DataType = typeof(decimal);
new_d_col.ColumnName = dr["日期"].ToString();
new_d_col.Caption = dr["日期"].ToString();
new_d_col.DefaultValue = 0;
new_DataTable.Columns.Add(new_d_col);
//这个的目的是为合计列构造expression
str_sum.Append("+[").Append("日期").Append("]");
}
//将合计列添加到新表中
new_d_col = new DataColumn();
new_d_col.DataType = typeof(decimal);
new_d_col.ColumnName = "Sum";
new_d_col.Caption = "合计";
new_d_col.DefaultValue = 0;
new_d_col.Expression = str_sum.ToString().substring(1);
new_DataTable.Columns.Add(new_d_col);
/*好了,到此新表已经构建完毕,下面开始为新表添加数据*/
//从原DataTable中读出不重复的客户名称,以客户名称为关键字来构造新表的行
DataTable distinct_object = _outDataSource.DefaultView.ToTable(true, "客户名称");
DataRow[] drs;
DataRow new_dr;
foreach (DataRow dr in distinct_object.Rows)
{
new_dr = new_DataTable.NewRow();
new_dr["客户名称"] = dr["客户名称"].ToString();
foreach (DataRow _dr in distinct_date.Rows)
{
drs = _outDataSource.Select("客户名称='" + dr["客户名称"].ToString() + "' and 日期='" + _dr["日期"].ToString() + "'");
if (drs.Length != 0)
{
new_dr[_dr["日期"].ToString()] = Math.Round(Convert.ToDecimal(drs[0]["金额"]), 2);
}
}
new_DataTable.Rows.Add(new_dr);
}
return new_DataTable;
}
从上面的代码中看到我们并没有为新表"合计"这一列赋值,这是因为该列具有表达式str_sum.Append("+[").Append("日期").Append("]"),所以这列的值是会自动填充的。
注意,在上面的表达式中,我们加了[],在DataTable的表达式中,如果列名是中文,一定要为列名加上[],要不然会报错的,这也是我调试了好久才发现的。
public DataTable RowsToCol(DataTable DT)
{
try
{
int rowCount=DT.Rows.Count;
int columnsCount=DT.Columns.Count;
DataTable result=new DataTable();
DataTable RowsDT=new DataTable();
DataTable COLSDT=new DataTable();
for(int i=0;i<RowCount;i++)
{
result.Columns.Add(DT.Rows[i][1].ToString());
RowsDT.Columns.Add(DT.Rows[i][1].ToString());
COLsDT.Columns.Add(DT.Rows[i][1].ToString());
}
string[] RowsName=new string[columnsCount];
for(int i=0;i<columnsCount;i++)
{
RowsName[i]=DT.Columns[i].ColumnName.Tostring();
}
for(int rowsi=0;rowsi<RowsName.Length;rowsi)
{
RowsDT.Rows.Add(new string[] {RowsName[rowsi]});
}
//行转列的核心部分
for(int columnsi=0;columnsi<columnsCount;columnsi++)
{
DataRow dr=COLsDT.NewRow();
for(int rowj=0;rowj<rowCount;rowj++)
{
dr[rowj]=DT.Rows[rowj][columnsi].toString();
}
COLsDT.Rows.Add(dr);
}
for(int columnsi=0;columnsi<columnsCount;columnsi++)
{
DataRow resultdr=result.NewRow();
for(int rowj=0;rowj<rowCount;rowj++)
{
if(rowj==0)
{
resultdr[rowj]=RowsDT.Rows[columnsi][0].ToString();
}
else
{
resultdr[rowj]=ColsDT.Rows[columnsi][rowj].ToString();
}
}
result.Rows.Add(resultdr);
}
return result;
}
catch(Exception ex)
{
throw new Exception(ex.ToString());
}
}
要转的DataTable结构如下图:
privateDataTableConvertDataTable(DataTable dtSrc)
{
try
{
DataTable dt =newDataTable();
dt.Columns.Add("姓名");
varcolumns = (frompindtSrc.Rows.Cast<DataRow>()selectp[1].ToString()).Distinct();
foreach(varitemincolumns) dt.Columns.Add(item);
vardata =fromkinsource.Rows.Cast<DataRow>()
groupkbyk[0]intom
selectnew{ Key = m.Key.ToString(), Items = m };
data.ToList().ForEach(n =>
{
string[] array =newstring[dt.Columns.Count];
array[0] = n.Key;
for(inti =1; i < dt.Columns.Count; i++)
array[i] = (frompinn.Items
wherep[1].ToString() == dt.Columns[i].ToString()
selectp[2].ToString())
.SingleOrDefault();
dt.Rows.Add(array);
});
returndt;
}
catch
{
returnnull;
}
}