ASP.NET实现类似Excel的数据透视表
数据透视表提供的数据三维视图效果,在Microsoft Excel能创建数据透视表,但是,它并不会总是很方便使用Excel。您可能希望在Web应用程序中创建一个数据透视报表。创建一个简单的数据透视表可能是一件非常复杂的任务。所以,我打算不但为你提供一个非常有用的工具创建简单和高级的数据透视表,而且为你移除一些笼罩他们的神秘面纱。
目标是:我们想要有能力将datatable中的二维的数据转换成三维视图。
在大多数情况下,你会从数据库的查询数据填充数据表,例如
代码
该查询会产生下面的数据表:
Sales Person |
Product |
Quantity |
Sale Amount |
John |
Pens |
200 |
350 |
John |
Pencils |
400 |
500 |
John |
Notebooks |
100 |
300 |
John |
Rulers |
50 |
100 |
John |
Calculators |
120 |
1200 |
John |
Back Packs |
75 |
1500 |
Jane |
Pens |
225 |
393.75 |
Jane |
Pencils |
335 |
418.75 |
Jane |
Notebooks |
200 |
600 |
Jane |
Rulers |
75 |
150 |
Jane |
Calculators |
80 |
800 |
Jane |
Back Packs |
97 |
1940 |
Sally |
Pens |
202 |
353.5 |
Sally |
Pencils |
303 |
378.75 |
Sally |
Notebooks |
198 |
600 |
Sally |
Rulers |
98 |
594 |
Sally |
Calculators |
80 |
800 |
Sally |
Back Packs |
101 |
2020 |
Sarah |
Pens |
112 |
196 |
Sarah |
Pencils |
245 |
306.25 |
Sarah |
Notebooks |
198 |
594 |
Sarah |
Rulers |
50 |
100 |
Sarah |
Calculators |
66 |
660 |
Sarah |
Back Packs |
50 |
2020 |
正如你所看到的,这是一个二维表,它不是一个非常有用的报表。因此,我们得改变,将它变成更可读的数据表。
数据透视表有3个面。
X轴构成了在表格上方的大标题。Y轴构成表的左栏,Z轴构成了X轴和Y轴对应的值。简单的数据透视表将会对每一个x轴值都只有一个z轴列,高级的数据透视表将对于每个X轴的值会对应有多个Z轴的值。
一个非常重要的一点是,Z轴的值只能是数字。这是因为Z轴值为横轴和纵轴的总额。使用一个非数值Z轴字段将抛出一个异常。
因此,如果你注意上面的数据表,你会发现,“Sales Person”和“Product”字段可以分配到的X轴或Y轴,但不能给z轴。在“Quantity”和“Sale Amount”字段可以被分配到z轴。
Pivot 类将数据表转换成html table。然后您可以将它输出到Web窗体上。那么,这只是实现的方法。如果你愿意,你可以根据这个类的逻辑创建一个用户控件。
这部分的代码是非常自我解释。 你能创建一个Pivot 对象,通过传递一个datatable作为参数。在init()方法只分配一个空字符串值给CSS变量。如果CSS的变量是一个空字符串,构造方法将使用默认的样式。每一个CSS变量都有一个相应的属性。
代码 private string FindValue(string xAxisField, string xAxisValue, string yAxisField, string yAxisValue, string zAxisField)
{
string zAxisValue = "";
try
{
foreach (DataRow row in _DataTable.Rows)
{
if (Convert.ToString(row[xAxisField]) == xAxisValue && Convert.ToString(row[yAxisField]) == yAxisValue)
{
zAxisValue = Convert.ToString(row[zAxisField]);
break;
}
}
}
catch
{
throw;
}
return zAxisValue;
}
在FindValue(...)方法在数据表中搜索的对应x轴和y轴值的Z轴值。xAxisField是X轴字段的列名(例如“Product”),而xAxisValue是在该列的值。该yAxisField是的Y轴字段的列名(例如“Sales Person”),并yAxisValue是在该列的值。该zAxisField是列名,在其中Z轴值,是您正在寻找地(例如“Sale Amount”)。
代码 private string[] FindValues(string xAxisField, string xAxisValue, string yAxisField, string yAxisValue, string[] zAxisFields)
{
int zAxis = zAxisFields.Length;
if (zAxis < 1)
zAxis++;
string[] zAxisValues = new string[zAxis];
//set default values
for (int i = 0; i <= zAxisValues.GetUpperBound(0); i++)
{
zAxisValues[i] = "0";
}
try
{
foreach (DataRow row in _DataTable.Rows)
{
if (Convert.ToString(row[xAxisField]) == xAxisValue && Convert.ToString(row[yAxisField]) == yAxisValue)
{
for (int z = 0; z < zAxis; z++)
{
zAxisValues[z] = Convert.ToString(row[zAxisFields[z]]);
}
break;
}
}
}
catch
{
throw;
}
return zAxisValues;
}
在FindValues(...)方法类似FindValue(...)方法,然而,它会返回多个z轴的值。这是用于高级的数据透视表,对应于x轴的值,您会有多个Z轴列。
这是CSS样式的方法之一。这在X轴上使用流行的样式(table的顶行)。如果您没有指定一个CSS类名给这个属性,该方法将使用默认的样式。 CSS类将会被应用到网页中的HTML table。
代码 /// <summary>
/// Creates an advanced 3D Pivot table.
/// </summary>
/// <param name="xAxisField">The main heading at the top of the report.</param>
/// <param name="yAxisField">The heading on the left of the report.</param>
/// <param name="zAxisFields">The sub heading at the top of the report.</param>
/// <returns>HtmlTable Control.</returns>
public HtmlTable PivotTable(string xAxisField, string yAxisField, string[] zAxisFields)
{
HtmlTable table = new HtmlTable();
//style table
TableStyle(table);
/*
* The x-axis is the main horizontal row.
* The z-axis is the sub horizontal row.
* The y-axis is the left vertical column.
*/
try
{
//get distinct xAxisFields
ArrayList xAxis = new ArrayList();
foreach (DataRow row in _DataTable.Rows)
{
if (!xAxis.Contains(row[xAxisField]))
xAxis.Add(row[xAxisField]);
}
//get distinct yAxisFields
ArrayList yAxis = new ArrayList();
foreach (DataRow row in _DataTable.Rows)
{
if (!yAxis.Contains(row[yAxisField]))
yAxis.Add(row[yAxisField]);
}
//create a 2D array for the y-axis/z-axis fields
int zAxis = zAxisFields.Length;
if (zAxis < 1)
zAxis = 1;
string[,] matrix = new string[(xAxis.Count * zAxis), yAxis.Count];
string[] zAxisValues = new string[zAxis];
for (int y = 0; y < yAxis.Count; y++) //loop thru y-axis fields
{
//rows
for (int x = 0; x < xAxis.Count; x++) //loop thru x-axis fields
{
//main columns
//get the z-axis values
zAxisValues = FindValues(xAxisField, Convert.ToString(xAxis[x])
, yAxisField, Convert.ToString(yAxis[y]), zAxisFields);
for (int z = 0; z < zAxis; z++) //loop thru z-axis fields
{
//sub columns
matrix[(((x + 1) * zAxis - zAxis) + z), y] = zAxisValues[z];
}
}
}
//calculate totals for the y-axis
decimal[] yTotals = new decimal[(xAxis.Count * zAxis)];
for (int col = 0; col < (xAxis.Count * zAxis); col++)
{
yTotals[col] = 0;
for (int row = 0; row < yAxis.Count; row++)
{
yTotals[col] += Convert.ToDecimal(matrix[col, row]);
}
}
//calculate totals for the x-axis
decimal[,] xTotals = new decimal[zAxis, (yAxis.Count + 1)];
for (int y = 0; y < yAxis.Count; y++) //loop thru the y-axis
{
int zCount = 0;
for (int z = 0; z < (zAxis * xAxis.Count); z++) //loop thru the z-axis
{
xTotals[zCount, y] += Convert.ToDecimal(matrix[z, y]);
if (zCount == (zAxis - 1))
zCount = 0;
else
zCount++;
}
}
for (int xx = 0; xx < zAxis; xx++) //Grand Total
{
for (int xy = 0; xy < yAxis.Count; xy++)
{
xTotals[xx, yAxis.Count] += xTotals[xx, xy];
}
}
//Build HTML Table
//Append main row (x-axis)
HtmlTableRow mainRow = new HtmlTableRow();
mainRow.Cells.Add(new HtmlTableCell());
for (int x = 0; x <= xAxis.Count; x++) //loop thru x-axis + 1
{
HtmlTableCell cell = new HtmlTableCell();
cell.ColSpan = zAxis;
if (x < xAxis.Count)
cell.InnerText = Convert.ToString(xAxis[x]);
else
cell.InnerText = "Grand Totals";
//style cell
MainHeaderTopCellStyle(cell);
mainRow.Cells.Add(cell);
}
table.Rows.Add(mainRow);
//Append sub row (z-axis)
HtmlTableRow subRow = new HtmlTableRow();
subRow.Cells.Add(new HtmlTableCell());
subRow.Cells[0].InnerText = yAxisField;
//style cell
SubHeaderCellStyle(subRow.Cells[0]);
for (int x = 0; x <= xAxis.Count; x++) //loop thru x-axis + 1
{
for (int z = 0; z < zAxis; z++)
{
HtmlTableCell cell = new HtmlTableCell();
cell.InnerText = zAxisFields[z];
//style cell
SubHeaderCellStyle(cell);
subRow.Cells.Add(cell);
}
}
table.Rows.Add(subRow);
//Append table items from matrix
for (int y = 0; y < yAxis.Count; y++) //loop thru y-axis
{
HtmlTableRow itemRow = new HtmlTableRow();
for (int z = 0 ; z <= (zAxis * xAxis.Count); z++) //loop thru z-axis + 1
{
HtmlTableCell cell = new HtmlTableCell();
if (z == 0) { cell.InnerText = Convert.ToString(yAxis[y]);
//style cell
MainHeaderLeftCellStyle(cell); } else { cell.InnerText = Convert.ToString(matrix[(z-1), y]);
//style cell
ItemCellStyle(cell); } itemRow.Cells.Add(cell); } //append x-axis grand totals
for (int z = 0; z < zAxis; z++) { HtmlTableCell cell = new HtmlTableCell(); cell.InnerText
= Convert.ToString(xTotals[z, y]);
//style cell
TotalCellStyle(cell); itemRow.Cells.Add(cell); } table.Rows.Add(itemRow); } //append y-axis totals
HtmlTableRow totalRow = new HtmlTableRow();
for (int x = 0; x <= (zAxis * xAxis.Count); x++) { HtmlTableCell cell = new HtmlTableCell();
if (x == 0) cell.InnerText
= "Totals";
else cell.InnerText
= Convert.ToString(yTotals[x-1]);
//style cell
TotalCellStyle(cell); totalRow.Cells.Add(cell); } //append x-axis/y-axis totals
for (int z = 0; z < zAxis; z++) { HtmlTableCell cell = new HtmlTableCell(); cell.InnerText
= Convert.ToString(xTotals[z, xTotals.GetUpperBound(1)]);
//style cell
TotalCellStyle(cell); totalRow.Cells.Add(cell); } table.Rows.Add(totalRow); } catch { throw; } return table; }
PivotTable(…) 方法,是所有神奇发生的地方。有两种重载方法,一个创建了一个简单的数据透视表,而其他(上面的方法)创建一个高级的数据透视表。唯一的区别在于,一个简单只有一个的z轴,而高级的,不止一个。
Pivot.zip文件中包括两个解决方案。Pivot 是一个类库解决方案是。您可以编译此解决方案和在Web应用程序中引用Pivot.dll。另一个解决方案是PivotTest,它是是一个ASP.NET应用程序。这说明如何实现Pivot类。
我已创建数据表的属性,它建立在上面的例子中的数据表。这只是用于演示目的。
代码 protected void Page_Load(object sender, EventArgs e)
{
//Advanced Pivot
Pivot advPivot = new Pivot(DataTableForTesting);
HtmlTable advancedPivot = advPivot.PivotTable("Sales Person", "Product", new string[] { "Sale Amount", "Quantity" });
div1.Controls.Add(advancedPivot);
//Simple Pivot
Pivot pivot = new Pivot(DataTableForTesting);
//override default style with css
pivot.CssTopHeading = "Heading";
pivot.CssLeftColumn = "LeftColumn";
pivot.CssItems = "Items";
pivot.CssTotals = "Totals";
pivot.CssTable = "Table";
HtmlTable simplePivot = pivot.PivotTable("Product", "Sales Person", "Sale Amount");
div2.Controls.Add(simplePivot);
}
上述代码包括两个实例化的pivot对象。第一个高级的pivot和第二是一个简单的pivot。你可以看到我已经为div添加了HtmlTable控件。我创建具有runat="server"属性的div,这样我可以在后台代码里面访问它。div只是帮助HtmlTable的定位。
使用默认样式的高级的数据透视表:
John | Jane | Sally | Sarah | Grand Totals | ||||||
Product | Sale Amount | Quantity | Sale Amount | Quantity | Sale Amount | Quantity | Sale Amount | Quantity | Sale Amount | Quantity |
Pens | 350 | 200 | 393.75 | 225 | 353.5 | 202 | 196 | 112 | 1293.25 | 739 |
Pencils | 500 | 400 | 418.75 | 335 | 378.75 | 303 | 306.25 | 245 | 1603.75 | 1283 |
Notebooks | 300 | 100 | 600 | 200 | 600 | 198 | 594 | 198 | 2094 | 696 |
Rulers | 100 | 50 | 150 | 75 | 594 | 98 | 100 | 50 | 944 | 273 |
Calculators | 1200 | 120 | 800 | 80 | 800 | 80 | 660 | 66 | 3460 | 346 |
Back Packs | 1500 | 75 | 1940 | 97 | 2020 | 101 | 2020 | 50 | 7480 | 323 |
Totals | 3950 | 945 | 4302.50 | 1012 | 4746.25 | 982 | 3876.25 | 721 | 16875.00 | 3660 |
使用自定义的CSS样式简单的数据透视表:
Sales Person |
Pens |
Pencils |
Notebooks |
Rulers |
Calculators |
Back Packs |
Grand Totals |
John |
350 |
500 |
300 |
100 |
1200 |
1500 |
3950 |
Jane |
393.75 |
418.75 |
600 |
150 |
800 |
1940 |
4302.50 |
Sally |
353.5 |
378.75 |
600 |
594 |
800 |
2020 |
4746.25 |
Sarah |
196 |
306.25 |
594 |
100 |
660 |
2020 |
3876.25 |
Totals |
1293.25 |
1603.75 |
2094 |
944 |
3460 |
7480 |
16875.00 |
参考原文:http://www.codeproject.com/KB/aspnet/Pivot.aspx
ASP.NET实现类似Excel的数据透视表的更多相关文章
- 【转】关于C#使用Excel的数据透视表的例子
收到消息,下星期又有导出 Excel 报表的代码要写.心想,不就是 OleDb 先 CREATE 表, 然后 INSERT 么?都是体力活啊...... 结果拿到纸张的报表,我就悲剧了.报表的结构,像 ...
- Excel学习 -- 数据透视表功能
Excel -- 数据透视表基础 数据透视表(Pivot Table)是一种交互式的表,可以进行某些计算,如求和与计数等.所进行的计算与数据跟数据透视表中的排列有关. 之所以称为数据透视表,是因 ...
- VSTO学习笔记(十四)Excel数据透视表与PowerPivot
原文:VSTO学习笔记(十四)Excel数据透视表与PowerPivot 近期公司内部在做一种通用查询报表,方便人力资源分析.统计数据.由于之前公司系统中有一个类似的查询使用Excel数据透视表完成的 ...
- 【技术分享:python 应用之一】如何使用 Python 对 Excel 做一份数据透视表
客户这边,其中有一张如同上图所示的数据汇总表,然而需求是,需要将这张表数据做一个数据透视表,最后通过数据透视表中的数据,填写至系统数据库.拿到需求,首先就想到肯定不能直接用设计器去操作 Excel,通 ...
- 【转载】使用Pandas创建数据透视表
使用Pandas创建数据透视表 本文转载自:蓝鲸的网站分析笔记 原文链接:使用Pandas创建数据透视表 目录 pandas.pivot_table() 创建简单的数据透视表 增加一个行维度(inde ...
- 我们无法找到服务器加载工作簿的数据模型"的 SharePoint 网站,当您刷新 Excel 2013 工作簿中的数据透视表时出错
假定您使用 Analysis Services 源在 Microsoft Excel 2013 中创建数据透视表.将 Excel 工作簿上载到 Microsoft SharePoint 网站中.当您尝 ...
- delphi 控制 EXCEL 数据透视表
虽说报表多又难做,做报表相当容易. 做报表也可以偷懒的,超级实用又省事.只需要做一个报表,这个报表里面包括几乎所有的数据字段,然后将查询到的数据导出到 excel中,利用excel自带的“数据透视”功 ...
- C# 操作Excel数据透视表
一.概述 数据透视表(Pivot Table)是一种交互式的表,可以进行某些计算,如求和与计数等,可动态地改变透视表版面布置,也可以重新安排行号.列标和页字段.当改变版面布置时,数据透视表也会按照新的 ...
- Excel如何快速统计一列中相同数值出现的个数--数据透视表
excel如何快速统计一列中相同数值出现的个数_百度经验 --这里介绍了两种解决方式,用第一种https://jingyan.baidu.com/article/9113f81b2c16822b321 ...
随机推荐
- Ubuntu Pycharm不能同时选中多行解决方法
转自http://blog.csdn.net/yaoqi_isee/article/details/77866309 问题描述 Pycharm和Sublime有一个很好用的特性就是可以同时选中多行进行 ...
- MAC 上搭建lua
下载和安装lua:(转自这里) 1. 下载最新版的lua-5.3.1.tar.gz 请点击(http://www.lua.org/ftp/),然后解压 2. 执行"终端"进入到 ...
- Spring Boot返回json数据及完美使用FastJson解析Json数据
Spring Boot返回json数据 视频地址:http://www.iqiyi.com/w_19rubxzsr5.html 博文参考:https://blog.csdn.net/linxingl ...
- php 设置自动加载某个页面
首先要找到Php.ini文件. 新建一个php文件,使用phpinfo(); 之后找到 Loaded Configuration File 指定的路径就是php.ini文件 打开文件,找到 auto_ ...
- 转 CAS实现SSO单点登录原理
原文链接 http://m.blog.csdn.net/hxpjava1/article/details/74019017 CAS 简介 1. 1.1. What is CAS ? CAS ( ...
- 在 IE 浏览器中,使用 bootstrap 使得页面滚动条浮动显示,自动隐藏,自动消失
貌似是从 IE10 开始?为了触屏操作优化浏览器的内容显示,IE 浏览器提供了一种可以浮动显示,自动隐藏的滚动条样式,但是这个样式会在某些情况下造成一些困扰,比如下图... 其实默认情况下,桌面版的 ...
- [hihoCoder] #1081 : 最短路径·一
时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 万圣节的早上,小Hi和小Ho在经历了一个小时的争论后,终于决定了如何度过这样有意义的一天——他们决定去闯鬼屋! 在鬼屋门口 ...
- c语言中使用宏,需要注意的的几点
使用#define来定义一些宏,进行一些简洁的替换甚至一些带参数的宏,在linux c代码中很常见,说明它很好.很有用, 但是它也有一些复杂的规矩和陷阱需要注意,下面我记录一些,仅供参考. 1.当使用 ...
- 关于modelsim时序仿真的几篇文章
1.http://wenku.baidu.com/view/386597f37c1cfad6195fa797.html 2.http://wenku.baidu.com/view/4b9521f9f7 ...
- protobuf c++入门
1.在.proto文件中定义消息格式 2.使用protobuf编译器 3.使用c++ api来读写消息 0.为何使用protobuf? 1.原始内存数据结构,可以以二进制方式sent/save ...