Pivot Table 是資料透視表的意思,如下一個普通的資料集:
<a href="http://images.cnblogs.com/cnblogs_com/Chinasf/WindowsLiveWriter/PivotTable_7B66/image_2.png"></a>
當按日期作為x軸,客戶ID作為y軸,利潤作為資料(SUM),轉換為資料透視表後呈現為:
<a href="http://images.cnblogs.com/cnblogs_com/Chinasf/WindowsLiveWriter/PivotTable_7B66/image_6.png"></a>
其中的利潤資料将被合計,而無資料的位置被“-”字元代替。
那麼實作一個這樣的資料展現模式,方法有多種,在排開專用工具軟體之外,一般存在三種方式:
一、使用支援多元展示資料的網格控件或報表控件。
二、編寫SQL來實作。
三、通過程式設計開發自定義的函數将資料做轉換。
這三種方式,它們各有優缺點:
一、使用網格控件則必須購買三方廠商開發的元件,而報表工具/元件則隻能在特定的場景應用并展示資料。
二、SQL方式隻是相對靈活,但如果x軸是動态的,如年月日,或者是某個項目(沒有參照表),就需要代碼來拼接SQL,不能寫死,但這種方式的功能卻很強大,像聚合函數之類的,通常在報表中,就是先寫SQL盡可能的接近于最終格式,再使用報表工具優化或處理資料格式。
三、程式設計方式,優點是可以很靈活的公開接口和實作需求,缺點是如果要做的完善,工作強度相對比較大(技術基礎,開發時間,可用性,穩定性,性能)。
通常要滿足一、二兩點,是相對容易的,而第三點程式設計方式相對來說,可利用的資源不多;因為最合适的還是自己根據項目需求而定制開發的。
那麼針對第三點程式設計方式的思路做以下講解:
一、資料透視表的x軸和y軸的
這裡的x軸和y軸表示為如圖:
<a href="http://images.cnblogs.com/cnblogs_com/Chinasf/WindowsLiveWriter/PivotTable_7B66/image_8.png"></a>
x軸的列提取:
<a href="http://images.cnblogs.com/cnblogs_com/Chinasf/WindowsLiveWriter/PivotTable_7B66/image_10.png"></a>
構造新記憶體表; 排除X軸字段和資料字段,将其他字段生成Y軸列; foreach (資料列 列 in 原始表.列集合) if (列名稱!=X軸字段 && 列名稱!=資料字段) 新記憶體表.增加列(列); 從資料中找出列字段值生成列; foreach (資料行 行 in 原始表.行集合) if (行[X軸字段]不存在) 新記憶體表.增加列(行[X軸字段]);
y軸的資料分組過濾和資料列填入:
<a href="http://images.cnblogs.com/cnblogs_com/Chinasf/WindowsLiveWriter/PivotTable_7B66/image_12.png"></a>
//周遊資料,填寫資料 { //比較分組列資料,保持唯一 string 比較值一 = 行[Y軸字段]; bool 存在相同 = 新記憶體表.行集合.查找(比較值一); //無相同的,則增加到分組資料集合 if (!存在相同) 構造記憶體表新行; //複制分組列資料 新行[Y軸列] = 行[Y軸列] ; } //查找資料列的資料 foreach (資料行 查找行 in 新記憶體表.行集合) string 比較值二 = 查找行[Y軸字段]; //如果和分組資料相同,則增加到對應的資料單元格 if (比較值一==比較值二) 查找行[行[X軸列] + ""] = 行[資料列];
二、資料列的聚合實作
聚合函數運算,思路是在填寫x軸的資料字段資料的時候,将它的原始值登記到一個運算表内,作為存儲;其中y軸資料作為key,x軸資料作為它子集的key,再在其中存放一個有序的List,其中存放的則是每行的原始資料值。
//聚合函數運算表
Dictionary<y軸列行資料, Dictionary<x軸列, List<x軸列資料集合>>> expressRows;
<a href="http://images.cnblogs.com/cnblogs_com/Chinasf/WindowsLiveWriter/PivotTable_7B66/image_14.png"></a>
此圖比較大,請配合下面的僞碼
//拿到了集合,後計算聚合函數和填充空文本 string 比較值二 =查找行[Y軸字段]; //查找需要計算的單元格 foreach (string x軸列 in x軸列集合) decimal avg, sum, max, min; avg = sum = max = min = 0; //排除空 if (聚合函數運算表.ContainsKey(比較值二) && 聚合函數運算表[比較值二].ContainsKey(x軸列)) //生成聚合結果 foreach (decimal d in 聚合函數運算表[比較值二][x軸列]) avg += d; sum += d; if (d > max) max = d; if (min == 0) min = d; if (min > d) min = d; //平均特殊處理 if (聚合函數運算表[比較值二][x軸列].Count > 0) avg = avg / 聚合函數運算表[比較值二][x軸列].Count; else avg = 0; //配置設定聚合結果 if (dataExpression != PivotDataExpression.None) switch (dataExpression) case PivotDataExpression.Avg: 查找行[x軸列] = avg; break; case PivotDataExpression.Max: 查找行[x軸列]= max; case PivotDataExpression.Sum: 查找行[x軸列]= sum; case PivotDataExpression.Min: 查找行[x軸列]= min; case PivotDataExpression.Count: 查找行[x軸列]= 聚合函數運算表[比較值二][x軸列].Count; //填充空文本 if (查找行.IsNull(x軸列)) 查找行[x軸列]= 空文本;
三、x軸和y軸的合計或公式套用的靈活實作
待續……
四、x軸和y軸的合計列實作
本文轉自suifei部落格園部落格,原文連結:http://www.cnblogs.com/Chinasf/archive/2008/04/13/1151368.html,如需轉載請自行聯系原作者