在SQLServer2005中實現表的行列轉換

2021-04-14 13:38:04 字數 4956 閱讀 2567

pivot和unpivot關係運算子是sql server 2005提供的新增功能,因此,對公升級到sql server 2005的資料庫使用pivot和unpivot時,資料庫的相容級別必須設定為90(可以使用sp_dbcmptlevel儲存過程設定相容級別)。

在查詢的from子句中使用pivot和unpivot,可以對乙個輸入錶值表示式執行某種操作,以獲得另一種形式的表。pivot運算子將輸入表的行旋轉為列,並能同時對行執行聚合運算。而unpivot運算子則執行與pivot運算子相反的操作,它將輸入表的列旋轉為行。

在from子句中使用pivot和unpivot關係運算子時的語法格式如下:

[ from [ ,...n ] ]

<table_source> ::=

<pivoted_table> ::=table_source pivot <pivot_clause> table_alias

<pivot_clause> ::=( aggregate_function ( value_column )

for pivot_column

in ( <column_list> )

) <unpivoted_table> ::=table_source unpivot <unpivot_clause> table_alias

<unpivot_clause> ::=( value_column for pivot_column in ( <column_list> ) )

<column_list> ::= column_name [ , ... ] table_source pivot <pivot_clause>

指定對table_source表中的pivot_column列進行透視。table_source可以是乙個表、表表示式或子查詢。

aggregate_function

系統或使用者定義的聚合函式。注意:不允許使用count(*)系統聚合函式。

value_column

pivot運算子用於進行計算的值列。與unpivot一起使用時,value_column不能是輸入table_source中的現有列的名稱。

for pivot_column

pivot運算子的透視列。pivot_column必須是可隱式或顯式轉換為nvarchar()的型別。

使用unpivot時,pivot_column是從table_source中提取輸出的列名稱,table_source中不能有該名稱的現有列。

in ( column_list )

在pivot子句中,column_list列出pivot_column中將成為輸出表的列名的值。

在unpivot子句中,column_list列出table_source中將被提取到單個pivot_column中的所有列名。

table_alias

輸出表的別名。

unpivot < unpivot_clause >

指定將輸入表中由column_list指定的多個列的值縮減為名為pivot_column的單個列。

常見的可能會用到pivot的情形是:需要生成交叉**報表以彙總資料。交叉表是使用較為廣泛的一種**式,例如,圖5-4所示的產品銷售表就是乙個典型的交叉表,其中的月份和產品種類都可以繼續新增。但是,這種格式在進行資料表儲存的時候卻並不容易管理,要儲存圖5-4這樣的**資料,資料表通常需要設計為圖5-5這樣的結構。這樣就帶來乙個問題,使用者既希望資料容易管理,又希望能夠生成一種能夠容易閱讀的**資料。好在pivot為這種轉換提供了便利。

圖5-4 產品銷售表 圖5-5 資料表結構

假設sales.orders表中包含有productid(產品id)、ordermonth(銷售月份)和subtotal(銷售額)列,並儲存有如表5-2所示的內容。

表5-2 sales.orders表中的內容

productid

ordermonth

subtotal 15

100.00

1 6

100.00

2 5

200.00 26

200.00

2 7

300.00 35

400.00 35

400.00

執行下面的語句:

select productid, [5] as 五月, [6] as 六月, [7] as 七月

from

sales.orders pivot

(sum (orders.subtotal)

for orders.ordermonth in

( [5], [6], [7] )

) as pvt

order by productid;

在上面的語句中,sales.orders是輸入表,orders.ordermonth是透視列(pivot_column),orders.subtotal是值列(value_column)。上面的語句將按下面的步驟獲得輸出結果集:

a.pivot首先按值列之外的列(productid和ordermonth)對輸入表sales.orders進行分組彙總,類似執行下面的語句:

select productid,

ordermonth,

sum (orders.subtotal) as sumsubtotal

from sales.orders

group by productid,ordermonth;

這時候將得到乙個如表5-3所示的中間結果集。其中只有productid為3的產品由於在5月有2筆銷售記錄,被累加到了一起(值為800)。

表5-3 sales.orders表經分組彙總後的結果

productid

ordermonth

sumsubtotal

1 5

100.00

1 6

100.00

2 5

200.00

2 6

200.00 27

300.00 35

800.00

b.pivot根據for orders.ordermonth in指定的值5、6、7,首先在結果集中建立名為5、6、7的列,然後從圖5-3所示的中間結果中取出ordermonth列中取出相符合的值,分別放置到5、6、7的列中。此時得到的結果集的別名為pvt(見語句中as pvt的指定)。結果集的內容如表5-4所示。

表5-4 使用for orders.ordermonth in( [5], [6], [7] )後得到的結果集

productid

5 6

7 1

100.00

100.00

null

2 200.00

200.00

200.00

3 800.00

null

null

c.最後根據select productid, [5] as 五月, [6] as 六月, [7] as 七月from的指定,從別名pvt結果集中檢索資料,並分別將名為5、6、7的列在最終結果集中重新命名為五月、六月、七月。這裡需要注意的是from的含義,其表示從經pivot關係運算子得到的pvt結果集中檢索資料,而不是從sales.orders中檢索資料。最終得到的結果集如表5-5所示。

表5-5 由表5-2所示的sales.orders表將行轉換為列得到的最終結果集

productid

五月六月

七月1

100.00

100.00

null

2 200.00

200.00

200.00

3 800.00

null

null

unpivot與pivot執行幾乎完全相反的操作,將列轉換為行。但是,unpivot並不完全是pivot的逆操作,由於在執行pivot過程中,資料已經被進行了分組彙總,所以使用unpivot並不會重現原始錶值表示式的結果。假設表5-5所示的結果集儲存在乙個名為mypvt的表中,現在需要將列識別符號「五月」、「六月」和「七月」轉換到對應於相應產品id的行值(即返回到表5-3所示的格式)。這意味著必須另外標識兩個列,乙個用於儲存月份,乙個用於儲存銷售額。為了便於理解,仍舊分別將這兩個列命名為ordermonth和sumsubtotal。參考下面的語句:

create table mypvt (productid int, 五月int, 六月 int, 七月int); --建立mypvt表

go--將表5-5中所示的值插入到mypvt表中

insert into mypvt values (1,100,100,0);

insert into mypvt values (2,200,200,200);

insert into mypvt values (3,800,0,0);

--執行unpivot

select productid, ordermonth, subtotal

from

mypvt unpivot

(subtotal for ordermonth in

(五月, 六月, 七月)

)as unpvt;

上面的語句將按下面的步驟獲得輸出結果集:

a.首先建立乙個臨時結果集的結構,該結構中包含mypvt表中除in (五月, 六月, 七月)之外的列,以及subtotal for ordermonth中指定的值列(subtotal)和透視列(ordermonth)。

b.將在mypvt中逐行檢索資料,將表的列名稱(在in (五月, 六月, 七月)中指定)放入ordermonth列中,將相應的值放入到subtotal列中。最後得到的結果集如表5-6所示。

表5-6 使用unpivot得到的結果集

productid

ordermonth

subtotal1五月

1001

六月100 1七月

0 2五月2002六月

200 2七月

200

3 五月

800 3六月

03 七月 0

With在sql server 2005中的用法

with在msdn中的講解,可以參考鏈結 1 2 建立錶值變數型別 3 4create type ty newareagoods as table 5 areaid int notnull,6 goodsid int notnull 7 8 9 創鍵返回今天 的資料 10 根據有 的地區獲取參 11...

在SQLServer 2005中編寫儲存過程

然而,在sql server 2005中,我們可以用.net家族的語言 主要是vb.net和c 來編寫儲存過程 以程式設計客棧及方法 觸發器和其它元件 讓我們來熟悉一下關於編寫儲存過程新方法的5個常見問題。它們是非常值得我們 的。1 為什麼我們必須使用clr模式來編寫儲存過程呢?主要原因是速度。sq...

在SQL Server2005中進行錯誤捕捉

任何程式都可能出現錯誤,在sql server中執行transact sql也不例外。如果在transact sql中發生了錯誤,一般有兩種捕捉錯誤的方法,一種是在客戶端 如 c delphi等 中使用類似try.catch的語句進行捕捉 另外一種就是在transact sql中利用transact...