轉(zhuǎn)帖|其它|編輯:郝浩|2010-07-22 11:53:19.000|閱讀 689 次
概述:數(shù)據(jù)透視表提供的數(shù)據(jù)三維視圖效果,在Microsoft Excel能創(chuàng)建數(shù)據(jù)透視表,但是,它并不會(huì)總是很方便使用Excel。您可能希望在Web應(yīng)用程序中創(chuàng)建一個(gè)數(shù)據(jù)透視報(bào)表。創(chuàng)建一個(gè)簡單的數(shù)據(jù)透視表可能是一件非常復(fù)雜的任務(wù)。所以,我打算不但為你提供一個(gè)非常有用的工具創(chuàng)建簡單和高級(jí)的數(shù)據(jù)透視表,而且為你移除一些籠罩他們的神秘面紗。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
數(shù)據(jù)透視表提供的數(shù)據(jù)三維視圖效果,在Microsoft Excel能創(chuàng)建數(shù)據(jù)透視表,但是,它并不會(huì)總是很方便使用Excel。您可能希望在Web應(yīng)用程序中創(chuàng)建一個(gè)數(shù)據(jù)透視報(bào)表。創(chuàng)建一個(gè)簡單的數(shù)據(jù)透視表可能是一件非常復(fù)雜的任務(wù)。所以,我打算不但為你提供一個(gè)非常有用的工具創(chuàng)建簡單和高級(jí)的數(shù)據(jù)透視表,而且為你移除一些籠罩他們的神秘面紗。
目標(biāo)是:我們想要有能力將datatable中的二維的數(shù)據(jù)轉(zhuǎn)換成 三維視圖。
在大多數(shù)情況下,你會(huì)從數(shù)據(jù)庫的查詢數(shù)據(jù)填充數(shù)據(jù)表,例如
SELECT
SalesPeople.FullName AS [Sales Person]
, Products.FullName AS [Product]
, SUM(Sales.SalesAmount) AS [Sale Amount]
, SUM(Sales.Qty) AS [Quantity]
FROM
Sales
JOIN
SalesPeople WITH (NOLOCK)
ON SalesPeople.SalesPersonID = Sales.SalesPersonID
JOIN
Products WITH (NOLOCK)
ON Products.ProductCode = Sales.ProductCode
GROUP BY
SalesPeople.FullName
, Products.FullName
該查詢會(huì)產(chǎn)生下面的數(shù)據(jù)表:
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 |
正如你所看到的,這是一個(gè)二維表,它不是一個(gè)非常有用的報(bào)表。因此,我們得改變,將它變成更可讀的數(shù)據(jù)表。
數(shù)據(jù)透視表有3個(gè)面:
X軸構(gòu)成了在表格上方的大標(biāo)題。Y軸構(gòu)成表的左欄,Z軸構(gòu)成了X軸和Y軸對(duì)應(yīng)的值。簡單的數(shù)據(jù)透視表將會(huì)對(duì)每一個(gè)x軸值都只有一個(gè)z軸列,高級(jí)的數(shù)據(jù)透視表將對(duì)于每個(gè)X軸的值會(huì)對(duì)應(yīng)有多個(gè)Z軸的值。
一個(gè)非常重要的一點(diǎn)是,Z軸的值只能是數(shù)字。這是因?yàn)閆軸值為橫軸和縱軸的總額。使用一個(gè)非數(shù)值Z軸字段將拋出一個(gè)異常。
因此,如果你注意上面的數(shù)據(jù)表,你會(huì)發(fā)現(xiàn),“Sales Person”和“Product”字段可以分配到的X軸或Y軸,但不能給z軸。在“Quantity”和“Sale Amount”字段可以被分配到z軸。
Pivot 類將數(shù)據(jù)表轉(zhuǎn)換成html table。然后您可以將它輸出到Web窗體上。那么,這只是實(shí)現(xiàn)的方法。如果你愿意,你可以根據(jù)這個(gè)類的邏輯創(chuàng)建一個(gè)用戶控件。
#region Variables
private DataTable _DataTable;
private string _CssTopHeading;
private string _CssSubHeading;
private string _CssLeftColumn;
private string _CssItems;
private string _CssTotals;
private string _CssTable;
#endregion Variables
#region Constructors
public Pivot(DataTable dataTable)
{
Init();
_DataTable = dataTable;
}
#endregion Constructors
這部分的代碼是非常自我解釋。 你能創(chuàng)建一個(gè)Pivot 對(duì)象,通過傳遞一個(gè)datatable作為參數(shù)。在init()方法只分配一個(gè)空字符串值給CSS變量。如果CSS的變量是一個(gè)空字符串,構(gòu)造方法將使用默認(rèn)的樣式。每一個(gè)CSS變量都有一個(gè)相應(yīng)的屬性。
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(...)方法在數(shù)據(jù)表中搜索的對(duì)應(yīng)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(...)方法,然而,它會(huì)返回多個(gè)z軸的值。這是用于高級(jí)的數(shù)據(jù)透視表,對(duì)應(yīng)于x軸的值,您會(huì)有多個(gè)Z軸列。
private void MainHeaderTopCellStyle(HtmlTableCell cell)
{
if (_CssTopHeading == "")
{
cell.Style.Add("font-family", "tahoma");
cell.Style.Add("font-size", "10pt");
cell.Style.Add("font-weight", "normal");
cell.Style.Add("background-color", "black");
cell.Style.Add("color", "white");
cell.Style.Add("text-align", "center");
}
else
cell.Attributes.Add("Class", _CssTopHeading);
}
這是CSS樣式的方法之一。這在X軸上使用流行的樣式(table的頂行)。如果您沒有指定一個(gè)CSS類名給這個(gè)屬性,該方法將使用默認(rèn)的樣式。 CSS類將會(huì)被應(yīng)用到網(wǎng)頁中的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(…) 方法,是所有神奇發(fā)生的地方。有兩種重載方法,一個(gè)創(chuàng)建了一個(gè)簡單的數(shù)據(jù)透視表,而其他(上面的方法)創(chuàng)建一個(gè)高級(jí)的數(shù)據(jù)透視表。唯一的區(qū)別在于,一個(gè)簡單只有一個(gè)的z軸,而高級(jí)的,不止一個(gè)。
Pivot.zip文件中包括兩個(gè)解決方案。Pivot 是一個(gè)類庫解決方案是。您可以編譯此解決方案和在Web應(yīng)用程序中引用Pivot.dll。另一個(gè)解決方案是PivotTest,它是是一個(gè)ASP.NET應(yīng)用程序。這說明如何實(shí)現(xiàn)Pivot類。
public DataTable DataTableForTesting
{
get
{
DataTable dt = new DataTable("Sales Table");
dt.Columns.Add("Sales Person");
dt.Columns.Add("Product");
dt.Columns.Add("Quantity");
dt.Columns.Add("Sale Amount");
dt.Rows.Add(new object[] { "John", "Pens", 200, 350.00 });
dt.Rows.Add(new object[] { "John", "Pencils", 400, 500.00 });
dt.Rows.Add(new object[] { "John", "Notebooks", 100, 300.00 });
dt.Rows.Add(new object[] { "John", "Rulers", 50, 100.00 });
dt.Rows.Add(new object[] { "John", "Calculators", 120, 1200.00 });
dt.Rows.Add(new object[] { "John", "Back Packs", 75, 1500.00 });
dt.Rows.Add(new object[] { "Jane", "Pens", 225, 393.75 });
dt.Rows.Add(new object[] { "Jane", "Pencils", 335, 418.75 });
dt.Rows.Add(new object[] { "Jane", "Notebooks", 200, 600.00 });
dt.Rows.Add(new object[] { "Jane", "Rulers", 75, 150.00 });
dt.Rows.Add(new object[] { "Jane", "Calculators", 80, 800.00 });
dt.Rows.Add(new object[] { "Jane", "Back Packs", 97, 1940.00 });
dt.Rows.Add(new object[] { "Sally", "Pens", 202, 353.50 });
dt.Rows.Add(new object[] { "Sally", "Pencils", 303, 378.75 });
dt.Rows.Add(new object[] { "Sally", "Notebooks", 198, 600.00 });
dt.Rows.Add(new object[] { "Sally", "Rulers", 98, 594.00 });
dt.Rows.Add(new object[] { "Sally", "Calculators", 80, 800.00 });
dt.Rows.Add(new object[] { "Sally", "Back Packs", 101, 2020.00 });
dt.Rows.Add(new object[] { "Sarah", "Pens", 112, 196.00 });
dt.Rows.Add(new object[] { "Sarah", "Pencils", 245, 306.25 });
dt.Rows.Add(new object[] { "Sarah", "Notebooks", 198, 594.00 });
dt.Rows.Add(new object[] { "Sarah", "Rulers", 50, 100.00 });
dt.Rows.Add(new object[] { "Sarah", "Calculators", 66, 660.00 });
dt.Rows.Add(new object[] { "Sarah", "Back Packs", 50, 2020.00 });
return dt;
}
}
我已創(chuàng)建數(shù)據(jù)表的屬性,它建立在上面的例子中的數(shù)據(jù)表。這只是用于演示目的。
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);
}
上述代碼包括兩個(gè)實(shí)例化的pivot對(duì)象。第一個(gè)高級(jí)的pivot和第二是一個(gè)簡單的pivot。你可以看到我已經(jīng)為div添加了HtmlTable控件。我創(chuàng)建具有runat="server"屬性的div,這樣我可以在后臺(tái)代碼里面訪問它。div只是幫助HtmlTable的定位。
使用默認(rèn)樣式的高級(jí)的數(shù)據(jù)透視表:
運(yùn)行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運(yùn)行]
使用自定義的CSS樣式簡單的數(shù)據(jù)透視表:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:轉(zhuǎn)載