日韩性视频-久久久蜜桃-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)...的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 色婷婷中文字幕 | 激情久久av | 亚洲精品在线一区二区 | 女生抠逼视频 | va免费视频| 国产精品毛片久久久久久久 | 中文字幕在线观看一区二区三区 | jzzijzzij亚洲成熟少妇在线播放 狠狠躁日日躁夜夜躁2022麻豆 | 都市激情自拍 | 午夜精品国产精品大乳美女 | 蜜臀久久99精品久久久久宅男 | 婷婷玖玖| 第一福利在线视频 | 午夜不卡在线观看 | 亚洲精品色图 | 丁香婷婷综合激情五月色 | 日韩免费视频网站 | 热久久91| 婷婷激情电影 | 色狠狠一区二区三区香蕉 | 日本三级欧美三级 | 日本黄在线 | 国产精品熟女一区二区不卡 | www.爱爱| 国产精品第五页 | 日本xxx在线播放 | 中国免费观看的视频 | 97在线播放免费观看 | 一二三区av| 欧美一区二区成人 | 亚洲欧美在线播放 | 99在线精品视频 | r级无码视频在线观看 | 91在线视频在线观看 | 黄色日b片| 久久看片网 | 欧美日韩高清在线观看 | 91精品国产麻豆 | 免费看黄色的网址 | 日韩在线观看视频一区 | 伦理片中文字幕 | 成人黄色一级片 | 亚洲伦理中文字幕 | 日本xxxx在线观看 | 国产三级a | 欧美成人69| 日本在线不卡一区二区 | 麻豆出品 | 久久99精品久久久久久园产越南 | 亚洲视频一二三四 | 五月av| 欧美日韩乱 | 特级做a爰片毛片免费69 | 精品国产成人av在线免 | 婷婷色视频 | 国产黄色小视频在线观看 | 精品一区二区人妻 | 色女人av | 国产成人高清在线 | 无码国产伦一区二区三区视频 | 国产3p在线播放 | 成年人的天堂 | 日本国产精品一区 | 被两个男人吃奶三p爽文 | 性欧美视频在线观看 | 色综合久久综合 | 亚洲AV无码一区二区三区少妇 | 久久这里只有精品首页 | 妖精视频一区二区三区 | 国产女无套免费视频 | 男女啪啪资源 | 天堂影院一区二区 | 在线国产区 | 曰本女人与公拘交酡 | 激情综合网激情 | 三日本三级少妇三级99 | 一区久久 | 高清av一区二区三区 | 亚洲自拍偷拍精品视频 | 色婷婷六月天 | 国外成人性视频免费 | 国内精品毛片 | 国产高清第一页 | 欧美一区二区三区久久精品 | 亚洲精品自拍视频 | 国产成人无码精品久久久性色 | 亚洲精品二 | 特级丰满少妇一级aaaa爱毛片 | www.香蕉视频在线观看 | 毛片毛片毛片毛片 | 精品乱子伦 | 在线视频精品免费 | 欧美成人一区二区三区高清 | 久色99| 日韩在线视频不卡 | 黄瓜视频成人 | 麻豆chinese极品少妇 | 国产精品高清在线 | 国产一区激情 |