【问题标题】:Adding Sum per row in PIVOT using LINQ使用 LINQ 在 PIVOT 中添加每行总和
【发布时间】:2012-12-29 19:42:35
【问题描述】:

我有以下将普通数据表转换为数据透视表的函数。

但我还有 1 个要求,它还应该显示 Value 列,即所有 Pivot 列单元格的总和。

e.g. : ORDER | SUM | PLANDATE
         1      50    10-Oct-2012
         1      10    10-Oct-2012
         2      15    12-Oct-2012

PIVOT 之后应该是这样的

ORDER | SUM | 10-Oct-2012 | 12-Oct-2012
  1      60     50            10
  2      15                   15

我的枢轴函数是:

DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
    // find primary key columns 
    //(i.e. everything but pivot column and pivot value)
    DataTable temp = dt.Copy();
    temp.Columns.Remove( pivotColumn.ColumnName );
    temp.Columns.Remove( pivotValue.ColumnName );
    string[] pkColumnNames = temp.Columns.Cast<DataColumn>()
        .Select( c => c.ColumnName )
        .ToArray();

    // prep results table
    DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
    result.PrimaryKey = result.Columns.Cast<DataColumn>().ToArray();
    dt.AsEnumerable()
        .Select(r => r[pivotColumn.ColumnName].ToString())
        .Distinct().ToList()
        .ForEach (c => result.Columns.Add(c, pivotColumn.DataType));

    // load it
    foreach( DataRow row in dt.Rows ) {
        // find row to update
        DataRow aggRow = result.Rows.Find(
            pkColumnNames
                .Select( c => row[c] )
                .ToArray() );
        // the aggregate used here is LATEST 
        // adjust the next line if you want (SUM, MAX, etc...)
        aggRow[row[pivotColumn.ColumnName].ToString()] = row[pivotValue.ColumnName];
    }

    return result;
}

谢谢,任何帮助都会得到帮助...

Sample Data :
 OrderStatus    Qty     Dated
    New 100 10-Oct-2012
    New 150 10-Oct-2012
    New 100 10-Oct-2012
    Conf    200 12-Oct-2012
    New 100 12-Oct-2012
    Reconf  300 12-Oct-2012
    New 200 15-Oct-2012
    New 200 15-Oct-2012
    Reconf  100 18-Oct-2012
    New 150 18-Oct-2012
    Conf    150 18-Oct-2012
    New 100 20-Oct-2012
    Reconf  500 20-Oct-2012
    New 100 30-Oct-2012
    New 700 30-Oct-2012
    New 100 30-Oct-2012
    Conf    100 10-Oct-2012

更新代码

 private DataTable DataTableToPivot(DataTable dtNormalTable, DataColumn pivotColumn, DataColumn valueColumn)
            {
                cTracing.WriteTrace("Inside DataTableToPivot", "DataTableToPivot");

                DataTable dtPivot = null;
                DataTable tempPivot = null;
                DataColumn sumColumn = new DataColumn();
                string[] pkColumnNames = null;

                try
                {
                    sumColumn.ColumnName = valueColumn.ColumnName;
                    sumColumn.DataType = typeof(string);
                    sumColumn.DefaultValue = "0";

var allrows = dt.AsEnumerable().Select(delegate(DataRow r)
            {
                DataRow nr = dt.NewRow();
                foreach (DataColumn item in dt.Columns)
                {
                    nr.SetField(item.ColumnName, r[item.ColumnName] is DBNull ? string.Empty : r[item.ColumnName]);
                }
                return nr;
            });

            dtNormalTable = allrows.CopyToDataTable();

                    // find primary key columns 
                    //(i.e. everything but pivot column and pivot value)
                    tempPivot = dtNormalTable.Copy();

                    tempPivot.Columns.Remove(pivotColumn.ColumnName);
                    tempPivot.Columns.Remove(valueColumn.ColumnName);

                    pkColumnNames = tempPivot.Columns
                                                 .Cast<DataColumn>()
                                                 .Select(c => c.ColumnName)
                                                 .ToArray();

                    // prep results table
                    dtPivot = tempPivot.DefaultView.ToTable(true, pkColumnNames).Copy();
                    dtPivot.PrimaryKey = dtPivot.Columns.Cast<DataColumn>().ToArray();
                    // include the sum column
                    dtPivot.Columns.Add(sumColumn);
                    try
                    {
                        dtNormalTable.AsEnumerable()
                          .Select(r => r[pivotColumn.ColumnName].ToString())
                          .Distinct()
                          .ToList()
                          .ForEach(c => dtPivot.Columns.Add(Convert.ToDateTime(c).ToString("dd-MMM-yyyy"), typeof(string)));
                    }
                    catch
                    {
                        dtNormalTable.AsEnumerable()
                          .Select(r => r[pivotColumn.ColumnName].ToString())
                          .Distinct()
                          .ToList()
                          .ForEach(c => dtPivot.Columns.Add(c, typeof(string)));
                    }

                    // load it
                    foreach (DataRow row in dtNormalTable.Rows)
                    {
                        // find row to update
                        DataRow aggRow = dtPivot.Rows.Find(
                            pkColumnNames
                                         .Select(c => row[c])
                                         .ToArray());
                        // the aggregate used here is LATEST 
                        // adjust the next line if you want (SUM, MAX, etc...)
                        string columnName = string.Empty;
                        try
                        {
                            columnName = Convert.ToDateTime(row[pivotColumn.ColumnName]).ToString("dd-MMM-yyyy");
                        }
                        catch
                        {
                            columnName = row[pivotColumn.ColumnName].ToString();
                        }

                        if (aggRow.IsNull(columnName))
                        {
                            aggRow[columnName] = Convert.ToDecimal(row[valueColumn.ColumnName]);
                        }
                        else
                        {
                            aggRow[columnName] = Convert.ToDecimal(aggRow[columnName]) +
                                                 Convert.ToDecimal(row[valueColumn.ColumnName]);
                        }

                        if (numberFormat == "3")
                        {
                            // add the value to the sum
                            aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
                                                Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0.000");
                        }
                        else if (numberFormat == "2")
                        {
                            // add the value to the sum
                            aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
                                                Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0.00");
                        }
                        else if (numberFormat == "1")
                        {
                            // add the value to the sum
                            aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
                                                Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0.0");
                        }
                        else
                        {
                            // add the value to the sum
                            aggRow[sumColumn] = (Convert.ToDecimal(aggRow[sumColumn].ToString()) +
                                                Convert.ToDecimal(row[valueColumn.ColumnName].ToString())).ToString("#0");
                        }
                    }

                    return dtPivot;
                }
                catch (Exception ex)
                {
                    cTracing.WriteTrace("Error inside DataTableToPivot", "DataTableToPivot");
                    cLogging.WriteLog(ex);
                    return null;
                }
                finally
                {
                    if (dtPivot != null)
                        dtPivot.Dispose();
                }
            }
enter code here

【问题讨论】:

    标签: linq c#-4.0


    【解决方案1】:

    如何将每一行的值添加到相应聚合行的总和列中?

    DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
        DataColumn sumColumn = new DataColumn();
        sumColumn.ColumnName = "SUM";
        sumColumn.DataType = typeof(int);
        sumColumn.DefaultValue = 0;
    
        // find primary key columns 
        //(i.e. everything but pivot column and pivot value)
        DataTable temp = dt.Copy();
        temp.Columns.Remove( pivotColumn.ColumnName );
        temp.Columns.Remove( pivotValue.ColumnName );
        string[] pkColumnNames = temp.Columns.Cast<DataColumn>()
            .Select( c => c.ColumnName )
            .ToArray();
    
        // prep results table
        DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
        result.PrimaryKey = result.Columns.Cast<DataColumn>().ToArray();
        // include the sum column
        result.Columns.Add(sumColumn);
        dt.AsEnumerable()
            .Select(r => r[pivotColumn.ColumnName].ToString())
            .Distinct()
            .OrderBy(c => Convert.ToDateTime(c))   // Order by the date
            .ToList()
            .ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
    
        // load it
        foreach( DataRow row in dt.Rows ) {
            // find row to update
            DataRow aggRow = result.Rows.Find(
                pkColumnNames
                    .Select( c => row[c] )
                    .ToArray() );
            // the aggregate used here is LATEST 
            // adjust the next line if you want (SUM, MAX, etc...)
            string columnName = row[pivotColumn.ColumnName].ToString();
            if(aggRow.IsNull(columnName))
            {
                aggRow[columnName] = (int)row[pivotValue.ColumnName];          
            }
            else
            {
                aggRow[columnName] = Convert.ToInt32(aggRow[columnName]) +
                                     (int)row[pivotValue.ColumnName];
            }   
            // add the value to the sum
            aggRow[sumColumn] = (int)aggRow[sumColumn] + 
                                (int)row[pivotValue.ColumnName];
        }
    
        return result;
    }
    

    【讨论】:

    • 它不工作,给出错误“指定的演员表无效。”在线: aggRow[sumColumnName] = (int)aggRow[sumColumnName] + (int)row[pivotValue.ColumnName];此外 aggRow[sumColumnName] 的值是 System.DBNull &它不是作为对象出现的字符串
    • @NikhilGupta:你的原始表中的 SUM 类型是什么?
    • 这是我的餐桌。 dtNormal.Columns.Add("OrderStatus"); dtNormal.Columns.Add("数量", typeof(int)); dtNormal.Columns.Add("日期"); dtNormal.Rows.Add("New", 100, "10-Oct-2012");
    • @NikhilGupta:我修复了 sumColumn 包含空值的问题。
    • Martin,我发现原始代码存在 1 个问题。如果您将在此代码上尝试我的示例日期,您将看到,它会计算总和,但不会显示所有列,例如如果状态为“新”且日期为“2012 年 10 月 10 日”,则有多个数量,这些数量没有加起来并导致错误的 PIVOT,你能帮忙吗:(
    猜你喜欢
    • 2013-08-13
    • 1970-01-01
    • 2020-02-11
    • 2023-03-22
    • 2014-09-05
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多