日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

重温SQL——行转列,列转行(转:http://www.cnblogs.com/kerrycode/archive/2010/07/28/1786547.html)...

發布時間:2023/12/9 数据库 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重温SQL——行转列,列转行(转:http://www.cnblogs.com/kerrycode/archive/2010/07/28/1786547.html)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
行轉列,列轉行是我們在開發過程中經常碰到的問題。行轉列一般通過CASE WHEN 語句來實現,也可以通過 SQL SERVER 2005 新增的運算符PIVOT來實現。 用傳統的方法,比較好理解。層次清晰,而且比較習慣。 但是PIVOT 、UNPIVOT提供的語法比一系列復雜的 SELECT...CASE 語句中所指定的語法更簡單、更具可讀性。下面我們通過幾個簡單的例子來介紹一下列轉行、行轉列問題。

我們首先先通過一個老生常談的例子,學生成績表(下面簡化了些)來形象了解下行轉列?

代碼 CREATE??TABLE?[StudentScores]
(
????
[UserName]?? ? ? ??NVARCHAR(20),????????--學生姓名
????[Subject]?? ? ? ? ?NVARCHAR(30),????????--科目
????[Score]????????????FLOAT,???????????????--成績
)

INSERT?INTO?[StudentScores]?SELECT?'Nick',?'語文',?80

INSERT?INTO?[StudentScores]?SELECT?'Nick',?'數學',?90

INSERT?INTO?[StudentScores]?SELECT?'Nick',?'英語',?70

INSERT?INTO?[StudentScores]?SELECT?'Nick',?'生物',?85

INSERT?INTO?[StudentScores]?SELECT?'Kent',?'語文',?80

INSERT?INTO?[StudentScores]?SELECT?'Kent',?'數學',?90

INSERT?INTO?[StudentScores]?SELECT?'Kent',?'英語',?70

INSERT?INTO?[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?dbo.[StudentScores]
GROUP?BY?UserName

查詢結果如圖所示,這樣我們就能很清楚的了解每位學生所有的成績了

?

?

接下來我們來看看第二個小列子。有一個游戲玩家充值表(僅僅為了說明,舉的一個小例子),

?代碼

CREATE?TABLE?[Inpours]
(
????
[ID]???????????? INT?IDENTITY(1,1),?
????
[UserName]?? ? ? ? ?NVARCHAR(20),??--游戲玩家
????[CreateTime]???? DATETIME,??????--充值時間????
????[PayType]???????? NVARCHAR(20),??--充值類型????
????[Money]?? ? ? ? ? ??DECIMAL,???????--充值金額
????[IsSuccess]?? ? ? ??BIT,???????????--是否成功?1表示成功,?0表示失敗
????CONSTRAINT?[PK_Inpours_ID]?PRIMARY?KEY(ID)
)

INSERT?INTO?Inpours?SELECT?'張三',?'2010-05-01',?'支付寶',?50,?1

INSERT?INTO?Inpours?SELECT?'張三',?'2010-06-14',?'支付寶',?50,?1

INSERT?INTO?Inpours?SELECT?'張三',?'2010-06-14',?'手機短信',?100,?1

INSERT?INTO?Inpours?SELECT?'李四',?'2010-06-14',?'手機短信',?100,?1

INSERT?INTO?Inpours?SELECT?'李四',?'2010-07-14',?'支付寶',?100,?1

INSERT?INTO?Inpours?SELECT?'王五',?'2010-07-14',?'工商銀行卡',?100,?1

INSERT?INTO?Inpours?SELECT?'趙六',?'2010-07-14',?'建設銀行卡',?100,?1

?


下面來了一個統計數據的需求,要求按日期、支付方式來統計充值金額信息。這也是一個典型的行轉列的例子。我們可以通過下面的腳本來達到目的 代碼 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

?

?如圖所示,我們這樣只是得到了這樣的輸出結果,還需進一步處理,才能得到想要的結果

代碼
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
)?T
GROUP?BY?CreateTime

?

其實行轉列,關鍵是要理清邏輯,而且對分組(Group by)概念比較清晰。上面兩個列子基本上就是行轉列的類型了。但是有個問題來了,上面是我為了說明弄的一個簡單列子。實際中,可能支付方式特別多,而且邏輯也復雜很多,可能涉及匯率、手續費等等(曾經做個這樣一個),如果支付方式特別多,我們的CASE WHEN 會弄出一大堆,確實比較惱火,而且新增一種支付方式,我們還得修改腳本如果把上面的腳本用動態SQL改寫一下,我們就能輕松解決這個問題?

代碼 DECLARE?@cmdText????VARCHAR(8000);
DECLARE?@tmpSql????????VARCHAR(8000);

SET?@cmdText?=?'SELECT?CONVERT(VARCHAR(10),?CreateTime,?120)?AS?CreateTime,'?+?CHAR(10);
SELECT?@cmdText?=?@cmdText?+?'?CASE?PayType?WHEN?'''?+?PayType?+?'''?THEN?SUM(Money)?ELSE?0?END?AS?'''?+?PayType?
????????????????
+?''','?+?CHAR(10)??FROM?(SELECT?DISTINCT?PayType?FROM?Inpours?)?T

SET?@cmdText?=?LEFT(@cmdText,?LEN(@cmdText)?-2)?--注意這里,如果沒有加CHAR(10)?則用LEFT(@cmdText,?LEN(@cmdText)?-1)

SET?@cmdText?=?@cmdText?+?'?FROM?Inpours?????GROUP?BY?CreateTime,?PayType?';

SET?@tmpSql?='SELECT?CreateTime,'?+?CHAR(10);
SELECT?@tmpSql?=?@tmpSql?+?'?ISNULL(SUM('?+?PayType??+?'),?0)?AS?'''?+?PayType??+?''','??+?CHAR(10)
????????????????????
FROM??(SELECT?DISTINCT?PayType?FROM?Inpours?)?T

SET?@tmpSql?=?LEFT(@tmpSql,?LEN(@tmpSql)?-2)?+?'?FROM?('?+?CHAR(10);

SET?@cmdText?=?@tmpSql?+?@cmdText?+?')?T?GROUP?BY?CreateTime?';
PRINT?@cmdText
EXECUTE?(@cmdText);

?

下面是通過PIVOT來進行行轉列的用法,大家可以對比一下,確實要簡單、更具可讀性(呵呵,習慣的前提下)

代碼 SELECT?
????????CreateTime,?
[支付寶]?,?[手機短信],
????????
[工商銀行卡]?,?[建設銀行卡]
FROM
(
????
SELECT?CONVERT(VARCHAR(10),?CreateTime,?120)?AS?CreateTime,PayType,?Money
????
FROM?Inpours
)?P
PIVOT?(
????????????
SUM(Money)
????????????
FOR?PayType?IN
????????????(
[支付寶],?[手機短信],?[工商銀行卡],?[建設銀行卡])
??????)?
AS?T
ORDER?BY?CreateTime

?

有時可能會出現這樣的錯誤:

消息 325,級別 15,狀態 1,第 9 行

'PIVOT' 附近有語法錯誤。您可能需要將當前數據庫的兼容級別設置為更高的值,以啟用此功能。有關存儲過程 sp_dbcmptlevel 的信息,請參見幫助。

這個是因為:對升級到 SQL Server 2005 或更高版本的數據庫使用 PIVOT 和 UNPIVOT 時,必須將數據庫的兼容級別設置為 90 或更高。有關如何設置數據庫兼容級別的信息,請參閱 。 例如,只需在執行上面腳本前加上 EXEC sp_dbcmptlevel Test, 90; 就OK了, Test 是所在數據庫的名稱。

?

下面我們來看看列轉行,主要是通過UNION ALL ,MAX來實現。假如有下面這么一個表

代碼 CREATE?TABLE?ProgrectDetail
(
????ProgrectName ? ? ? ??
NVARCHAR(20),?--工程名稱
????OverseaSupply????????INT,??????????--海外供應商供給數量
????NativeSupply ? ? ? ??INT,??????????--國內供應商供給數量
????SouthSupply??????????INT,??????????--南方供應商供給數量
????NorthSupply ? ? ? ? ?INT???????????--北方供應商供給數量
)

INSERT?INTO?ProgrectDetail
SELECT?'A',?100,?200,?50,?50
UNION?ALL
SELECT?'B',?200,?300,?150,?150
UNION?ALL
SELECT?'C',?159,?400,?20,?320
UNION?ALL
SELECT?'D',?250,?30,?15,?15

?

?我們可以通過下面的腳本來實現,查詢結果如下圖所示

代碼 SELECT?ProgrectName,?'OverseaSupply'?AS?Supplier,
????????
MAX(OverseaSupply)?AS?'SupplyNum'
FROM?ProgrectDetail
GROUP?BY?ProgrectName
UNION?ALL
SELECT?ProgrectName,?'NativeSupply'?AS?Supplier,
????????
MAX(NativeSupply)?AS?'SupplyNum'
FROM?ProgrectDetail
GROUP?BY?ProgrectName
UNION?ALL
SELECT?ProgrectName,?'SouthSupply'?AS?Supplier,
????????
MAX(SouthSupply)?AS?'SupplyNum'
FROM?ProgrectDetail
GROUP?BY?ProgrectName
UNION?ALL
SELECT?ProgrectName,?'NorthSupply'?AS?Supplier,
????????
MAX(NorthSupply)?AS?'SupplyNum'
FROM?ProgrectDetail
GROUP?BY?ProgrectName

?

?

UNPIVOT 實現如下:

代碼 SELECT?ProgrectName,Supplier,SupplyNum
FROM?
(
????
SELECT?ProgrectName,?OverseaSupply,?NativeSupply,
???????????SouthSupply,?NorthSupply
?????
FROM?ProgrectDetail
)T
UNPIVOT?
(
????SupplyNum?
FOR?Supplier?IN
????(OverseaSupply,?NativeSupply,?SouthSupply,?NorthSupply?)
)?P

總結

以上是生活随笔為你收集整理的重温SQL——行转列,列转行(转:http://www.cnblogs.com/kerrycode/archive/2010/07/28/1786547.html)...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产青青操 | 日本黄色三级 | 欧美三区四区 | 91久久久久久久久久久久久 | 亚洲wwww | 99re这里 | 伊人激情综合网 | 国产主播在线一区 | 天天干视频在线观看 | 欧美国产乱视频 | 免费国产视频 | 欧美日韩在线视频免费 | 亚洲精品水蜜桃 | 91精品国自产 | 欧美高清videos高潮hd | 人人澡人人澡 | 色婷婷yy | 一区二区三区日韩 | 蘑菇视频黄色 | 日本免费一区二区三区视频 | 国产4区| 在线观看亚洲区 | 夜夜躁日日躁狠狠久久av | 黑鬼巨鞭白妞冒白浆 | 日本伦理片在线播放 | 性感少妇av| 在线观看亚洲免费视频 | 蜜色视频 | 亚洲v| 亚洲涩综合 | 国产又粗又长又黄视频 | 健身教练巨大粗爽gay视频 | 91精品婷婷国产综合久久 | 日韩成人精品 | 亚洲色成人网站www永久四虎 | 国产一级生活片 | 精品国产一二 | 日韩一级二级三级 | 国产偷啪 | 女人性做爰24姿势视频 | 91视频专区 | 黄色香蕉视频 | 加勒比hezyo黑人专区 | 亚洲不卡中文字幕无码 | 婷婷成人综合网 | 亚欧毛片 | 欧美激情视频在线观看 | 伊人网欧美| 欧美黄大片 | 国产特黄一级片 | 三级不卡视频 | 手机看片欧美日韩 | 91香蕉国产在线观看软件 | 日韩电影第一页 | 婷婷色婷婷开心五月四房播播 | 欧美成人免费网站 | 琪琪av在线 | 美女一区二区视频 | 亚洲女同志亚洲女同女播放 | 青娱乐国产盛宴 | 另类色综合 | 亚洲欧洲免费 | 国产一区不卡在线 | 天天看片中文字幕 | 国产手机av | 在线看中文字幕 | 日韩成人av网址 | 熟女少妇在线视频播放 | 精品国产鲁一鲁一区二区张丽 | 国产天堂久久 | 肥婆大荫蒂欧美另类 | 精品久久久久久久久久久国产字幕 | 无码人妻丰满熟妇精品 | 亚洲精品尤物 | 亚洲一级特黄毛片 | 免费观看黄色网 | 欧美韩日一区二区 | 成人一区二区三区在线观看 | 欧美 日韩 国产 在线观看 | 18视频在线观看娇喘 | 成人在线观看av | 国产欧美一区二区三区另类精品 | 2023av在线| 欧美一区二区三区成人久久片 | 色香色香欲天天天影视综合网 | 精品产国自在拍 | 91麻豆国产福利精品 | 免费观看成年人网站 | 爱乃なみ加勒比在线播放 | 黄色录像a级片 | 岛国av噜噜噜久久久狠狠av | 人妻丝袜一区二区三区 | 激情黄色小视频 | www.蜜桃av.com| 免费成人深夜夜 | 日本少妇高潮抽搐 | 中文字幕在线网站 | 欧美乱大交xxxxx春色视频 | a级片免费播放 |