艾伟_转载:透视Datatable

  源代码:/Files/zhuqil/PivotDataTable.zip 

  现在,以表格的形式显示的数据是任何应用程序的重要组成部分。但有时你需要以数据行格式显示大量的数据。如果行数巨大,它变得非常难以分析。在这种情况下,您可能希望使用其他格式统计你的数据,如: charts, graphs, groups, pivots等 。本文将介绍一种使用适当的聚合函数的方式来透视你的数据,它可以很容易提高您的报表功能。

  下面的截图是在GridView中显示的数据透视功能。(关于数据透视还可以参考:ASP.NET实现类似Excel的数据透视表

  为了简化方案,我把表的结果分三个区域显示:RowField, DataField, 和ColumnFields,除了这些,Pivot类提供一些供您来选择的聚合函数来绑定的数据。可提供的选项有:

Count: 返回匹配的数据数量

Sum: 返回匹配的数据总和(为了得到总和,将DataField的类型必须转换为decimal类型)

First: 返回匹配的数据第一项

Last: 返回匹配的数据最后一项

Average: 返回匹配的数据平均(为了得到平均值,将DataField的类型必须转换为decimal类型)

Max: 返回匹配的数据最大值

Min: 返回匹配的数据最小值

Exists: 如果有匹配的数据,返回“true”,否则“false”

  代码主要包含了一个名字为"Pivot"的类,在它的构造函数中创建DataTable。 ColumnFields 是一个字符串数组参数,它允许你透视多列数据。这个类还包含了一个实际透视你数据的PivotData() 方法。

代码

public DataTable PivotData(string RowField, string DataField, 
       AggregateFunction Aggregate, params string[] ColumnFields)
{
    DataTable dt = new DataTable();
    string Separator = ".";
    var RowList = (from x in _SourceTable.AsEnumerable() 
        select new { Name = x.Field<object>(RowField) }).Distinct();
    var ColList = (from x in _SourceTable.AsEnumerable() 
                   select new { Name = ColumnFields.Select(n => x.Field<object>(n))
                       .Aggregate((a, b) => a += Separator + b.ToString()) })
                       .Distinct()
                       .OrderBy(m => m.Name);

    dt.Columns.Add(RowField);
    foreach (var col in ColList)
    {
        dt.Columns.Add(col.Name.ToString());
    }

    foreach (var RowName in RowList)
    {
        DataRow row = dt.NewRow();
        row[RowField] = RowName.Name.ToString();
        foreach (var col in ColList)
        {
            string strFilter = RowField + " = '" + RowName.Name + "'";
            string[] strColValues = 
              col.Name.ToString().Split(Separator.ToCharArray(), 
                                        StringSplitOptions.None);
            for (int i = 0; i < ColumnFields.Length; i++)
                strFilter += " and " + ColumnFields[i] + 
                             " = '" + strColValues[i] + "'";
            row[col.Name.ToString()] = GetData(strFilter, DataField, Aggregate);
        }
        dt.Rows.Add(row);
    }
    return dt;
}

  首先,该函数通过获取RowList的Distinct的值,确定行的成员;通过获取ColList的Distinct值,确定列的成员。然后,创建datatable的列。然后根据所提供的聚合函数,遍历每一行和获取匹配值到相应的单元格上。调用GetData()函数,检索匹配值。

代码

private object GetData(string Filter, string DataField, AggregateFunction Aggregate)
{
    try
    {
        DataRow[] FilteredRows = _SourceTable.Select(Filter);
        object[] objList = 
         FilteredRows.Select(x => x.Field<object>(DataField)).ToArray();

        switch (Aggregate)
        {
            case AggregateFunction.Average:
                return GetAverage(objList);
            case AggregateFunction.Count:
                return objList.Count();
            case AggregateFunction.Exists:
                return (objList.Count() == 0) ? "False" : "True";
            case AggregateFunction.First:
                return GetFirst(objList);
            case AggregateFunction.Last:
                return GetLast(objList);
            case AggregateFunction.Max:
                return GetMax(objList);
            case AggregateFunction.Min:
                return GetMin(objList);
            case AggregateFunction.Sum:
                return GetSum(objList);
            default:
                return null;
        }
    }
    catch (Exception ex)
    {
        return "#Error";
    }
    return null;
}

这个函数首先过滤到DataRow []数组中匹配RowField和ColumnFields数据 ,然后调用相应的聚合函数。

  如何使用代码:

  代码使用起来很简单。创建一个Pivot类的实例,然后使用要求的参数调用PivotData方法。PivotData()方法返回DataTable,他可直接作为GridView的数据源。

代码

DataTable dt = ExcelLayer.GetDataTable("_Data\\DataForPivot.xls", "Sheet1$");
Pivot pvt = new Pivot(dt);

grdPivot.DataSource = pvt.PivotData("Designation", "CTC", 
   AggregateFunction.Max, "Company", "Department", "Year");
grdPivot.DataBind();

示例中使用的数据库是一个Excel Sheet ,放在示例应用程序的根文件夹下的“_Data”文件夹中。

    该MergeHeader函数创建合并头部的单元格,并提供了一个简化的外观。

代码

private void MergeHeader(GridView gv, GridViewRow row, int PivotLevel)
{
    for (int iCount = 1; iCount <= PivotLevel; iCount++)
    {
        GridViewRow oGridViewRow = new GridViewRow(0, 0, 
          DataControlRowType.Header, DataControlRowState.Insert);
        var Header = (row.Cells.Cast<tablecell>()
            .Select(x => GetHeaderText(x.Text, iCount, PivotLevel)))
            .GroupBy(x => x);

        foreach (var v in Header)
        {
            TableHeaderCell cell = new TableHeaderCell();
            cell.Text = v.Key.Substring(v.Key.LastIndexOf(_Separator) + 1);
            cell.ColumnSpan = v.Count();
            oGridViewRow.Cells.Add(cell);
        }
        gv.Controls[0].Controls.AddAt(row.RowIndex, oGridViewRow);
    }
    row.Visible = false;
}

  该函数为每个PivotLevel创建新行,和相应的合并。 PivotLevel这里是列上的轴完成的数量。

  Header从一个数组中得到所有的列值,对GetHeaderText()返回的重复的值进行分组,根据HeaderText的重复数量,设置新创建的单元格的ColumnSpan属性。将单元格添加到GridViewRow中。最后添加GridViewRow到GridView。GetHeaderText() 函数根据PivotLevel返回header text.

  例如,假设一个透视表,完成三个ColumnField: Company, Department, 和Year。GridView的初始化时候,头部将拥有Company.Department。PivotLevel 1是Year。 GetHeaderText()将返回Company。对于PivotLevel 2,GetHeaderText()将返回Company.Department。对于PivotLevel 3,GetHeaderText()将返回Company.Department.Year,等等...

  以下是GridView的截图,包含三个层次透视数据:

  代码帮助您合并你想要的格式GridView的头单元格。对于初学者,在ExcelLayer.GetDataTable()方法将是一个从Excel表中的中获得数据例子。

  目前,代码只在DataTable中透视数据。该代码将得到加强,将来透视IListSource或ICollection派生的任何对象。

  参考原文:http://www.codeproject.com/KB/aspnet/PivotDataTable.aspx

时间: 2024-10-10 14:28:01

艾伟_转载:透视Datatable的相关文章

艾伟_转载:DataTable.NewRow 内存泄漏问题

昨天做了一个自动生成Insert 语句的小工具,今天测试发现存在严重的内存泄漏问题,代码看了好几遍,没发现问题.后来用 .Net Memory Profiler 跟踪(跟踪方法见 用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇) 发现有数千个DataRow 没有释放,最后定位是DataTable.NewRow 的问题. 先看一下有问题的代码 public DataRow GetNextRow(){if (_DataReader.Read()) { Da

艾伟_转载:ASP.NET实现类似Excel的数据透视表

    代码:/Files/zhuqil/Pivot.zip     数据透视表提供的数据三维视图效果,在Microsoft Excel能创建数据透视表,但是,它并不会总是很方便使用Excel.您可能希望在Web应用程序中创建一个数据透视报表.创建一个简单的数据透视表可能是一件非常复杂的任务.所以,我打算不但为你提供一个非常有用的工具创建简单和高级的数据透视表,而且为你移除一些笼罩他们的神秘面纱.    目标是:我们想要有能力将datatable中的二维的数据转换成三维视图.    在大多数情况

艾伟_转载:基于.NET平台的Windows编程实战(五)—— 问卷管理功能的实现

本系列文章导航 基于.NET平台的Windows编程实战(一)--前言 基于.NET平台的Windows编程实战(二)-- 需求分析与数据库设计 基于.NET平台的Windows编程实战(四)-- 数据库操作类的编写 基于.NET平台的Windows编程实战(五)-- 问卷管理功能的实现 基于.NET平台的Windows编程实战(六)-- 题目管理功能的实现 首先,为了使我们的界面更加便于操作及布局,我们引入第三开源控件DockPanel[当然也可以不引入控件而直接进行开发],你可以从这里:Do

艾伟_转载:基于.NET平台的Windows编程实战(四)—— 数据库操作类的编写

本系列文章导航 基于.NET平台的Windows编程实战(一)--前言 基于.NET平台的Windows编程实战(二)-- 需求分析与数据库设计 基于.NET平台的Windows编程实战(四)-- 数据库操作类的编写 基于.NET平台的Windows编程实战(五)-- 问卷管理功能的实现 基于.NET平台的Windows编程实战(六)-- 题目管理功能的实现 大家都知道本系统的正常运行少不了数据库操作这一块,且其在本系统中具有决定性作用,可以说没有它的操作系统将无法运行,故在本节课程中,专门把针

艾伟_转载:数组排序方法的性能比较(上):注意事项及试验

昨天有朋友写了一篇文章,其中比较了List的Sort方法与LINQ中排序方法的性能,而最终得到的结果是"LINQ排序方法性能高于List.Sort方法".这个结果不禁让我很疑惑.因为List.Sort方法是改变容器内部元素的顺序,而LINQ排序后得到的是一个新的序列.假如两个排序方法的算法完全一致,LINQ排序也比对方多出元素复制的开销,为什么性能反而会高?如果LINQ排序的算法/实现更为优秀,那为什么.NET Fx不将List.Sort也一并优化一下呢?于是今天我也对这个问题进行了简

艾伟_转载:一个MVC分页Helper

本人写的一个分页Helper,支持普通分页(也就是,首页.上一页.下一页.末页等),综合分页(普通分页和数字分页的综合).下面是分页效果: 分页代码: PagerHelper.cs 代码   1 using System;  2  using System.Collections.Generic;  3 using System.Collections.Specialized;  4 using System.Linq;  5 using System.Web;  6 using System.

艾伟_转载:WCF版的PetShop之三:实现分布式的Membership和上下文传递

本系列文章导航 WCF版的PetShop之一:PetShop简介 WCF版的PetShop之二:模块中的层次划分 WCF版的PetShop之三:实现分布式的Membership和上下文传递 通过上一篇了解了模块内基本的层次划分之后,接下来我们来聊聊PetShop中一些基本基础功能的实现,以及一些设计.架构上的应用如何同WCF进行集成.本篇讨论两个问题:实现分布式的Membership和客户端到服务端上下文(Context)的传递. 一. 如何实现用户验证 对登录用户的验证是大部分应用所必需的,对

艾伟_转载:一次挂死(hang)的处理过程及经验

 前言:        CPU占用率低,内存还有许多空余,但网站无法响应,这就是网站挂死,通常也叫做hang.这种情况对于我这样既是CEO,又是CTO,还兼职扫地洗碗的个人站长来说根本就是家常便饭.以下是一次处理hang的经验及总结,前后用了一个月,不仅涉及程序排查,数据库优化,还有硬件升级的苦恼.其中辛酸苦辣只有经历过的站长才能体会,希望此文能对各位有所帮助!        首先介绍一下网站基本情况,是一个在线小说阅读网站,每天有一定页面访问量,在优化开始前由两台服务器运行,均为Dell Po

艾伟_转载:从ASP.NET的PHP执行速度比较谈起

上星期我在InfoQ发表了一篇新闻,对Joe Stagner在博客上发表的三篇关于ASP.NET与PHP性能对比的文章进行了总结.写新闻其实挺不爽的,因为不能夹杂个人的看法,只能平铺直叙陈述事实.当然,如果像某些新闻那样"换一种说法"是可以骗过一些"不明真相的群众",但是这就有违道德了.因此,在客观陈述完新闻内容之后,我只能选择把自己的感想.评论等内容放在自己的博客上. Joe Stagner的背景挺特殊,它是PHP的老用户,在ASP.NET出现之前就是PHP的重量