行轉列與列轉行的使用 pivot與unpivot

2021-08-30 23:46:54 字數 4971 閱讀 6123

1.使用pivot進行報表的行轉列 收藏

行轉列在報表中是用的很多的,以前在sql中使用橫轉列的時候總是使用selet case來處理,即便sql2005現在都要被sql2008代替了,偶還一次沒有用過他提供的新東東pivot。一時興起,還是學了學。

有兩個簡化的表(**商表和供貨記錄表)

create table supplier (sid int,suppliershortname varchar(20))--記錄**商的簡稱和**

create table warehouserecord (sid int,materialid int,qty numeric(18,2),price numeric(18,4),billdate smalldatetime)--記錄每天**商的送貨記錄

管理需求上下面這個是經常遇到的,需要知道最近乙個月或一周內每個**商的供貨情況,可能需要得到的表樣式是下面的

日期         **商a供貨金額  **商b供貨金額  **商c供貨金額 .....

2008-11-25         300.2           250.0            2562.65

我們建立好錶後填入記錄,開始下面的工作

--寫入**商記錄

insert into supplier (sid,suppliershortname) select 1,'**商a'

insert into supplier (sid,suppliershortname) select 2,'**商b'

insert into supplier (sid,suppliershortname) select 3,'**商c'

--送貨記錄

insert into warehouserecord (sid,materialid,qty,price,billdate) select 1,10000,200,5.4,'2008-11-25'

insert into warehouserecord (sid,materialid,qty,price,billdate) select 2,11000,30,95.4,'2008-11-25'

insert into warehouserecord (sid,materialid,qty,price,billdate) select 1,15000,50,6.32,'2008-11-25'

insert into warehouserecord (sid,materialid,qty,price,billdate) select 3,11000,220,9.2,'2008-11-25'

要達到我們需要的效果,如果還是使用sql 2000中的方式我們也很容易

select c.billdate,

sum(case when c.suppliershortname='**商a' then c.qty*c.price else 0 end) as **商a,

sum(case when c.suppliershortname='**商b' then c.qty*c.price else 0 end) as **商b,

sum(case when c.suppliershortname='**商c' then c.qty*c.price else 0 end) as **商c

from (select a.suppliershortname,b.* from supplier a,warehouserecord b where a.sid=b.sid) c group by c.billdate

這樣就可以得到我們的結果了,如果**商比較多,是不是有點長了。

寫完了sql2000的,現在如果換成了sql2005的pivot,則是如何寫的呢?

select billdate,[**商a],[**商b],[**商c] from

(select a.suppliershortname,sum(b.qty*b.price) as daymoney,b.billdate from supplier a,warehouserecord b where a.sid=b.sid group by b.billdate,a.suppliershortname) c

pivot (sum(daymoney) for suppliershortname in ([**商a],[**商b],[**商c])) as unpvt

看起來好像只是語句短了點,其他的差別不大吧。

上面兩種方法寫的都是固定欄位的,如果**商很多,或者要監控的**商是一直變化的,按上面那樣方法寫還不死人啊。

對於不固定列的,sql2000是如何寫的呢?

declare @sql varchar(8000)

set @sql = 'select billdate '

select @sql = @sql + ' , sum(case c.suppliershortname when ''' + suppliershortname + ''' then c.price*c.qty else 0 end) [' + suppliershortname + ']'

from (select distinct suppliershortname from supplier) as a

set @sql = @sql + ' from (select a.suppliershortname,b.* from supplier a,warehouserecord b where a.sid=b.sid) c  group by c.billdate'

exec(@sql)

執行的結果就和上面的一樣了。

那麼使用sql2005提供的新方法pivot又是如何寫的呢?

declare @selstr varchar(1000)

declare @sql varchar(8000)

select @selstr = isnull(@selstr + ',','')+ '['+ltrim(suppliershortname)+']'

from (select suppliershortname from supplier) d

set @sql='select billdate,'+@selstr+' from (select a.suppliershortname,b.billdate,sum(b.qty*b.price) as daymoney from supplier a,warehouserecord b where a.sid=b.sid group by b.billdate,a.suppliershortname) c '

set @sql=@sql+'pivot (sum(daymoney) for suppliershortname in ('+@selstr+')) as unpvt'

print @sql

exec(@sql)

感覺出差別來了沒有?

說真的,就自己的感覺,我還是覺得以前的方法比較好理解一點。也許人總是活著習慣中,當你習慣一種方法時,改變是真的有點困難,除非你努力將新方法成為了你新的習慣。

2..pivot的用法體會:

語句範例:

select pn,[2006/5/30] as [20060530],[2006/6/2] as [20060602]

from consumptiondata a

pivot (sum(a.m_qty) for a.m_date in ([2006/5/30],[2006/6/2])) as pvt

order by pn

table結構 consumptiondata (pn,m_date,m_qty)

order by pn可要可不要,並不重要,只是排序的作用

關鍵的是紅色部分,解析如下,select 大家都知道,pn是 consumptiondata表中的乙個column,

[2006/5/30]也是乙個column,他需要顯示成[20060530],注意[2006/5/30]不是乙個value,而是乙個column.[2006/6/2]與[2006/5/30]一樣.

pivot ( ........... ) as pvt這個結構是固定格式,沒有什麼需要特殊說明的,當然pvt隨便你給他乙個nickname ,it doesn't make any differences.

sum(a.m_qty) 是我們希望顯示出來的值,注意這個地方必須用彙總函式,否則語法不會過.

for a.m_date in ([2006/5/30],[2006/6/2])

for 表示彙總的值要顯示在哪乙個column下面

如果我們想讓sum(m_qty)顯示在pn轉換的column下面,則可寫為for pn, in 的清單表示我們關注哪些要檢視的column,注意再次強調是column,不是value. in的清單是column清單,不是value清單,是m_date的value轉換成的column清單. 

2.unpivot

--此段可以直接在sql 2005中執行

create table pvt (vendorid int, emp1 int, emp2 int,

e*** int, emp4 int, emp5 int)

goinsert into pvt values (1,4,3,5,4,4)

insert into pvt values (2,4,1,5,5,5)

insert into pvt values (3,4,3,5,4,4)

insert into pvt values (4,4,2,5,5,4)

insert into pvt values (5,5,1,5,5,5)

go --select * from pvt

--unpivot the table.

select vendorid, employee, orders

from pvt

unpivot (

orders for employee in ([emp1], [emp2], [e***], [emp4], [emp5])

)as unpvt

go

行轉列 列轉行

行轉列 select t.t.rowid from test1 t id c1 c2 c3 1 小紅 數學 10 2 小紅 語文 20 3 小欄 數學 15 4 小欄 語文 25 test1 oracle select c1,to char wm concat c2 c2 from test1 gr...

Oracle 行轉列與列轉行

oracel 行轉列與列轉行 一 列轉行 1.使用函式 wm concat 2.函式說明 該函式將某一列,根據條件轉換成一行 相當於把列裡的值合併,並用逗號區分各個值 3.例子 表 testt 中有資料如下所示 xh age 1 11 1 12 1 13 2 21 2 22 3 31 sql sel...

MySQL行轉列與列轉行

建表 新增資料 create table test tb grade id int 10 not null auto increment,user name varchar 20 default null,course varchar 20 default null,score float defa...