程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> ASP.NET實現類似Excel的數據透視表

ASP.NET實現類似Excel的數據透視表

編輯:.NET實例教程


代碼:Pivot.zip

數據透視表提供的數據三維視圖效果,在Microsoft Excel能創建數據透視表,但是,它並不會總是很方便使用Excel。您可能希望在Web應用程序中創建一個數據透視報表。創建一個簡單的數據透視表可能是一件非常復雜的任務。所以,我打算不但為你提供一個非常有用的工具創建簡單和高級的數據透視表,而且為你移除一些籠罩他們的神秘面紗。

目標是:我們想要有能力將datatable中的二維的數據轉換成三維視圖。

在大多數情況下,你會從數據庫的查詢數據填充數據表,例如

以下為引用的內容:

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

該查詢會產生下面的數據表:

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窗體上。那麼,這只是實現的方法。如果你願意,你可以根據這個類的邏輯創建一個用戶控件。

以下為引用的內容:

#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

這部分的代碼是非常自我解釋。 你能創建一個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軸列。

以下為引用的內容:

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的頂行)。如果您沒有指定一個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類。

以下為引用的內容:

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; 
    } 
}

我已創建數據表的屬性,它建立在上面的例子中的數據表。這只是用於演示目的。

以下為引用的內容:

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的定位。

使用默認樣式的高級的數據透視表:

運行代碼:

<table >
<tbody>
<tr>
<td></td>
<td colSpan="2">John</td>
<td colSpan="2">Jane</td>
<td colSpan="2">Sally</td>
<td colSpan="2">Sarah</td>
<td colSpan="2">Grand Totals</td></tr>
<tr>
<td >Product</td>
<td >Sale Amount</td>
<td >Quantity</td>
<td >Sale Amount</td>
<td >Quantity</td>
<td >Sale Amount</td>
<td >Quantity</td>
<td >Sale Amount</td>
<td >Quantity</td>
<td >Sale Amount</td>
<td >Quantity</td></tr>
<tr>
<td >Pens</td>
<td >350</td>
<td >200</td>
<td >393.75</td>
<td >225</td>
<td >353.5</td>
<td >202</td>
<td >196</td>
<td >112</td>
<td >1293.25</td>
<td >739</td></tr>
<tr>
<td >Pencils</td>
<td >500</td>
<td >400</td>
<td >418.75</td>
<td >335</td>
<td >378.75</td>
<td >303</td>
<td >306.25</td>
<td >245</td>
<td >1603.75</td>
<td >1283</td></tr>
<tr>
<td >Notebooks</td>
<td >300</td>
<td >100</td>
<td >600</td>
<td >200</td>
<td >600</td>
<td >198</td>
<td >594</td>
<td >198</td>
<td >2094</td>
<td >696</td></tr>
<tr>
<td >Rulers</td>
<td >100</td>
<td >50</td>
<td >150</td>
<td >75</td>
<td >594</td>
<td >98</td>
<td >100</td>
<td >50</td>
<td >944</td>
<td >273</td></tr>
<tr>
<td >Calculators</td>
<td >1200</td>
<td >120</td>
<td >800</td>
<td >80</td>
<td >800</td>
<td >80</td>
<td >660</td>
<td >66</td>
<td >3460</td>
<td >346</td></tr>
<tr>
<td >Back Packs</td>
<td >1500</td>
<td >75</td>
<td >1940</td>
<td >97</td>
<td >2020</td>
<td >101</td>
<td >2020</td>
<td >50</td>
<td >7480</td>
<td >323</td></tr>
<tr>
<td >Totals</td>
<td >3950</td>
<td >945</td>
<td >4302.50</td>
<td >1012</td>
<td >4746.25</td>
<td >982</td>
<td >3876.25</td>
<td >721</td>
<td >16875.00</td>
<td >3660</td></tr></tbody></table>

使用自定義的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

代碼:Pivot.zip

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved