SQL 行轉列


行轉列,列轉行是我們在開發過程中經常碰到的問題。
1、行轉列一般通過CASE WHEN 語句來實現
2、也可以通過 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
View Code

如果我想知道每位學生的每科成績,而且每個學生的全部成績排成一行,這樣方便我查看、統計,導出數據

1、case when 方式

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
查詢結果如圖所示,這樣我們就能很清楚的了解每位學生所有的成績了

 

2、PIVOT方式

SELECT * FROM [StudentScores] /*數據源*/
AS P
PIVOT 
(
    SUM(Score/*行轉列后 列的值*/) FOR 
    p.Subject/*需要行轉列的列*/ IN ([語文],[數學],[英語],[生物]/*列的值*/)
) AS T

另舉一例做解釋:

SELECT [星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日]
--這里是PIVOT第三步(選擇行轉列后的結果集的列)這里可以用“*”表示選擇所有列,也可以只選擇某些列(也就是某些天),通過TBL來定義列的別名

FROM WEEK_INCOME
 --這里是PIVOT第二步驟(准備原始的查詢結果,因為PIVOT是對一個原始的查詢結果集進行轉換操作,所以先查詢一個結果集出來)這里可以是一個select子查詢,
 --但為子查詢時候要指定別名,否則語法錯誤

PIVOT
(
    SUM(INCOME) for [week] in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])
--這里是PIVOT第一步驟,也是核心的地方,進行行轉列操作。聚合函數SUM表示你需要怎樣處理轉換后的列的值,是總和(sum),還是平均(avg)還是min,max等等。
--例如如果week_income表中有兩條數據並且其week都是“星期一”,其中一條的income是1000,另一條income是500,那么在這里使用sum,行轉列后“星期一”這個列的值當然是1500了。
--后面的for [week] in([星期一],[星期二]...)中 for [week]就是說將week列的值分別轉換成一個個列,也就是“以值變列”。
--但是需要轉換成列的值有可能有很多,我們只想取其中幾個值轉換成列,那么怎樣取呢?就是在in里面了,比如我此刻只想看工作日的收入,在in里面就只寫“星期一”至“星期五”
--(注意,in里面是原來week列的值,"以值變列")。總的來說,SUM(INCOME) for [week] in([星期一],[星期二],[星期三],[星期四],[星期五],[星期六],[星期日])這句的意思直譯出來,
--就是說:將列[week]值為"星期一","星期二","星期三","星期四","星期五","星期六","星期日"分別轉換成列,這些列的值取income的總和。

)TBL
--別名一定要寫

 

二、列轉行

1、測試數據准備

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
View Code

 

  

sql語句:

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

 結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM