近一段時間一直沒怎麼看過sql了,突襲一下:
行轉列,列轉行是我們在開發過程中經常碰到的問題。行轉列一般通過case when 語句來實現,也可以通過 sql server 2005 新增的運算子pivot來實現。 用傳統的方法,比較好理解。層次清晰,而且比較習慣。 但是pivot 、unpivot提供的語法比一系列複雜的 select...case 語句中所指定的語法更簡單、更具可讀性。下面我們通過幾個簡單的例子來介紹一下列轉行、行轉列問題。
首先通過乙個老生常談的例子,學生成績表(下面簡化了些)來形象了解下行轉列
createtable[studentscores]
([username] nvarchar(20),--學生姓名
[subject] nvarchar(30),--科目
[score]float,--成績
)insertinto[studentscores]select'nick','語文',80
insertinto[studentscores]select'nick','數學',90
insertinto[studentscores]select'nick','英語',70
insertinto[studentscores]select'nick','生物',85
insertinto[studentscores]select'kent','語文',80
insertinto[studentscores]select'kent','數學',90
insertinto[studentscores]select'kent','英語',70
insertinto[studentscores]select'kent','生物',85
現在想知道每位學生的每科成績,而且每個學生的全部成績排成一行,這樣方便檢視、統計,匯出資料
select username,max( case subject when'語文'then score else 0 end)as '語文',
max(case subject when'數學'then score else 0 end)as'數學',
max(case subject when'英語'then score else 0 end)as'英語',
max(case subject when'生物'then score else 0 end)as'生物' from
[studentscores]
group by username
有乙個遊戲玩家充值表(僅僅為了說明,舉的乙個小例子),
**createtable[inpours]
([id]intidentity(1,1),
[username] nvarchar(20),--遊戲玩家
[createtime]datetime,--充值時間
[paytype]nvarchar(20),--充值型別
[money] decimal,--充值金額
[issuccess] bit,--是否成功1表示成功,0表示失敗
constraint[pk_inpours_id]primarykey(id)
)insertintoinpoursselect'張三','2010-05-01','支付寶',50,1
insertintoinpoursselect'張三','2010-06-14','支付寶',50,1
insertintoinpoursselect'張三','2010-06-14','手機簡訊',100,1
insertintoinpoursselect'李四','2010-06-14','手機簡訊',100,1
insertintoinpoursselect'李四','2010-07-14','支付寶',100,1
insertintoinpoursselect'王五','2010-07-14','工商銀行卡',100,1
insertintoinpoursselect'趙六','2010-07-14','建設銀行卡',100,1
統計資料的需求,要求按日期、支付方式來統計充值金額資訊,指令碼如下:
select
createtime,
isnull(sum([支付寶]),0)as[支付寶],
isnull(sum([手機簡訊]),0)as[手機簡訊],
isnull(sum([工商銀行卡]),0)as[工商銀行卡],
isnull(sum([建設銀行卡]),0)as[建設銀行卡]
from
(select convert(varchar(10),createtime,120)as createtime,
case paytype when'支付寶'then sum(money)else 0 end as'支付寶',
case paytype when'手機簡訊'then sum(money)else 0 end as'手機簡訊',
case paytype when'工商銀行卡'then sum(money)else 0 end as'工商銀行卡',
case paytype when'建設銀行卡'then sum(money)else 0 end as'建設銀行卡'
from inpours
group by createtime,paytype
)tgroup by createtime
其實行轉列,關鍵是要理清邏輯,而且對分組(group by)概念比較清晰。上面兩個列子基本上就是行轉列的型別了。但是有個問題來了,上面是我為了說明弄的乙個簡單列子。實際中,可能支付方式特別多,而且邏輯也複雜很多,可能涉及匯率、手續費等等(曾經做個這樣乙個),如果支付方式特別多,我們的case when 會弄出一大堆,確實比較惱火,而且新增一種支付方式,我們還得修改指令碼如果把上面的指令碼用動態sql改寫一下,我們就能輕鬆解決這個問題
declare@cmdtextvarchar(8000);
declare@tmpsqlvarchar(8000);
set@cmdtext='selectconvert(varchar(10),createtime,120)ascreatetime,'+char(10);
select@cmdtext=@cmdtext+'casepaytypewhen'''+paytype+'''thensum(money)else0endas'''+paytype
+''','+char(10)from(selectdistinctpaytypefrominpours)t
set@cmdtext=left(@cmdtext,len(@cmdtext)-2)--注意這裡,如果沒有加char(10)則用left(@cmdtext,len(@cmdtext)-1)
set@cmdtext=@cmdtext+'frominpoursgroupbycreatetime,paytype';
set@tmpsql='selectcreatetime,'+char(10);
select@tmpsql=@tmpsql+'isnull(sum('+paytype+'),0)as'''+paytype+''','+char(10)
from(selectdistinctpaytypefrominpours)t
set@tmpsql=left(@tmpsql,len(@tmpsql)-2)+'from('+char(10);
set@cmdtext=@tmpsql+@cmdtext+')tgroupbycreatetime';
print@cmdtext
execute(@cmdtext);
下面是通過pivot來進行行轉列的用法
select
createtime,[支付寶],[手機簡訊],
[工商銀行卡],[建設銀行卡]
from
(selectconvert(varchar(10),createtime,120)ascreatetime,paytype,money
frominpours
)ppivot(
sum(money)
forpaytypein
([支付寶],[手機簡訊],[工商銀行卡],[建設銀行卡])
)ast
orderbycreatetime
有時可能會出現這樣的錯誤:
訊息 325,級別 15,狀態 1,第 9 行
'pivot' 附近有語法錯誤。您可能需要將當前資料庫的相容級別設定為更高的值,以啟用此功能。有關儲存過程 sp_dbcmptlevel 的資訊,請參見幫助。
這個是因為:對公升級到 sql server 2005 或更高版本的資料庫使用 pivot 和 unpivot 時,必須將資料庫的相容級別設定為 90 或更高。有關如何設定資料庫相容級別的資訊,請參閱 sp_dbcmptlevel (transact-sql)。 例如,只需在執行上面指令碼前加上 exec sp_dbcmptlevel test, 90; 就ok了, test 是所在資料庫的名稱。
SQL中行轉列 列轉行
sql行轉列 列轉行 這個主題還是比較常見的,行轉列主要適用於對資料作聚合統計,如統計某類目的商品在某個時間區間的銷售情況。整理測試資料 create table wyc test id int 32 not null auto increment name varchar 80 default n...
mysql中行轉列
1 mysql中可以行轉列。通過group concat 函式。如 select group concat name from resources group by type 將name列的值轉化為一行,2 預設是之間用逗號隔開,還可以自定義符號來作為隔開。如使用 來隔開。如 select grou...
SQL2005中行轉列
sql2005中有函式可以直接將行轉列,這樣行轉列就好做多了。但是數值列和文字列稍有不同。1 文字列示例 create table tb 姓名 varchar 10 課程 varchar 10 分數 int insert into tb values 張三 語文 74 insert into tb ...