1. 程式人生 > >SQL 查詢怎麼將行變成列

SQL 查詢怎麼將行變成列

表有三列,stunamem,subject score.
表中的資料有:
張三 語文 0
李四 語文 4
王二 英文 90
張三 數學 333
要求查詢結果如下
學生 語文 英文 數學
張三 0 0 333
李四 4 0 0
沒有分數的預設為0


求查詢SQL

等樓下.

使用 case when

SQL code

/*

標題:普通行列轉換(version 2.0)

作者:愛新覺羅.毓華(十八年風雨,守得冰山雪蓮花開)

時間:2008-03-09

地點:廣東深圳

說明:普通行列轉換(version 1.0)僅針對sql server 2000提供靜態和動態寫法,version 2.0增加sql server 2005的有關寫法。



問題:假設有張學生成績表(tb)如下:

姓名 課程 分數

張三 語文 74

張三 數學 83

張三 物理 93

李四 語文 74

李四 數學 84

李四 物理 94

想變成(得到如下結果):

姓名 語文 數學 物理

---- ---- ---- ----

李四 74 84 94

張三 74 83 93

-------------------

*/



create table tb(姓名 varchar(10) , 課程 varchar(10) , 分數 int)

insert into tb values('張三' , '語文' , 74)

insert into tb values('張三' , '數學' , 83)

insert into tb values('張三' , '物理' , 93)

insert into tb values('李四' , '語文' , 74)

insert into tb values('李四' , '數學' , 84)

insert into tb values('李四' , '物理' , 94)

go



--SQL SERVER 2000 靜態SQL,指課程只有語文、數學、物理這三門課程。(以下同)

select 姓名 as 姓名 ,

max(case 課程 when '語文' then 分數 else 0 end) 語文,

max(case 課程 when '數學' then 分數 else 0 end) 數學,

max(case 課程 when '物理' then 分數 else 0 end) 物理

from tb

group by 姓名



--SQL SERVER 2000 動態SQL,指課程不止語文、數學、物理這三門課程。(以下同)

declare @sql varchar(8000)

set @sql = 'select 姓名 '

select @sql = @sql + ' , max(case 課程 when ''' + 課程 + ''' then 分數 else 0 end) [' + 課程 + ']'

from (select distinct 課程 from tb) as a

set @sql = @sql + ' from tb group by 姓名'

exec(@sql)



--SQL SERVER 2005 靜態SQL。

select * from (select * from tb) a pivot (max(分數) for 課程 in (語文,數學,物理)) b



--SQL SERVER 2005 動態SQL。

declare @sql varchar(8000)

select @sql = isnull(@sql + '],[' , '') + 課程 from tb group by 課程

set @sql = '[' + @sql + ']'

exec ('select * from (select * from tb) a pivot (max(分數) for 課程 in (' + @sql + ')) b')



---------------------------------



/*

問題:在上述結果的基礎上加平均分,總分,得到如下結果:

姓名 語文 數學 物理 平均分 總分

---- ---- ---- ---- ------ ----

李四 74 84 94 84.00 252

張三 74 83 93 83.33 250

*/



--SQL SERVER 2000 靜態SQL。

select 姓名 姓名,

max(case 課程 when '語文' then 分數 else 0 end) 語文,

max(case 課程 when '數學' then 分數 else 0 end) 數學,

max(case 課程 when '物理' then 分數 else 0 end) 物理,

cast(avg(分數*1.0) as decimal(18,2)) 平均分,

sum(分數) 總分

from tb

group by 姓名



--SQL SERVER 2000 動態SQL。

declare @sql varchar(8000)

set @sql = 'select 姓名 '

select @sql = @sql + ' , max(case 課程 when ''' + 課程 + ''' then 分數 else 0 end) [' + 課程 + ']'

from (select distinct 課程 from tb) as a

set @sql = @sql + ' , cast(avg(分數*1.0) as decimal(18,2)) 平均分 , sum(分數) 總分 from tb group by 姓名'

exec(@sql)



--SQL SERVER 2005 靜態SQL。

select m.* , n.平均分 , n.總分 from

(select * from (select * from tb) a pivot (max(分數) for 課程 in (語文,數學,物理)) b) m,

(select 姓名 , cast(avg(分數*1.0) as decimal(18,2)) 平均分 , sum(分數) 總分 from tb group by 姓名) n

where m.姓名 = n.姓名



--SQL SERVER 2005 動態SQL。

declare @sql varchar(8000)

select @sql = isnull(@sql + ',' , '') + 課程 from tb group by 課程

exec ('select m.* , n.平均分 , n.總分 from

(select * from (select * from tb) a pivot (max(分數) for 課程 in (' + @sql + ')) b) m ,

(select 姓名 , cast(avg(分數*1.0) as decimal(18,2)) 平均分 , sum(分數) 總分 from tb group by 姓名) n

where m.姓名 = n.姓名')



drop table tb



------------------

------------------



/*

問題:如果上述兩表互相換一下:即表結構和資料為:

姓名 語文 數學 物理

張三 74  83  93

李四 74  84  94

想變成(得到如下結果):

姓名 課程 分數

---- ---- ----

李四 語文 74

李四 數學 84

李四 物理 94

張三 語文 74

張三 數學 83

張三 物理 93

--------------

*/



create table tb(姓名 varchar(10) , 語文 int , 數學 int , 物理 int)

insert into tb values('張三',74,83,93)

insert into tb values('李四',74,84,94)

go



--SQL SERVER 2000 靜態SQL。

select * from

(

select 姓名 , 課程 = '語文' , 分數 = 語文 from tb

union all

select 姓名 , 課程 = '數學' , 分數 = 數學 from tb

union all

select 姓名 , 課程 = '物理' , 分數 = 物理 from tb

) t

order by 姓名 , case 課程 when '語文' then 1 when '數學' then 2 when '物理' then 3 end



--SQL SERVER 2000 動態SQL。

--呼叫系統表動態生態。

declare @sql varchar(8000)

select @sql = isnull(@sql + ' union all ' , '' ) + ' select 姓名 , [課程] = ' + quotename(Name , '''') + ' , [分數] = ' + quotename(Name) + ' from tb'

from syscolumns

where name! = N'姓名' and ID = object_id('tb') --表名tb,不包含列名為姓名的其它列

order by colid asc

exec(@sql + ' order by 姓名 ')



--SQL SERVER 2005 動態SQL。

select 姓名 , 課程 , 分數 from tb unpivot (分數 for 課程 in([語文] , [數學] , [物理])) t



--SQL SERVER 2005 動態SQL,同SQL SERVER 2000 動態SQL。



--------------------

/*

問題:在上述的結果上加個平均分,總分,得到如下結果:

姓名 課程 分數

---- ------ ------

李四 語文 74.00

李四 數學 84.00

李四 物理 94.00

李四 平均分 84.00

李四 總分 252.00

張三 語文 74.00

張三 數學 83.00

張三 物理 93.00

張三 平均分 83.33

張三 總分 250.00

------------------

*/



select * from

(

select 姓名 as 姓名 , 課程 = '語文' , 分數 = 語文 from tb

union all

select 姓名 as 姓名 , 課程 = '數學' , 分數 = 數學 from tb

union all

select 姓名 as 姓名 , 課程 = '物理' , 分數 = 物理 from tb

union all

select 姓名 as 姓名 , 課程 = '平均分' , 分數 = cast((語文 + 數學 + 物理)*1.0/3 as decimal(18,2)) from tb

union all

select 姓名 as 姓名 , 課程 = '總分' , 分數 = 語文 + 數學 + 物理 from tb

) t

order by 姓名 , case 課程 when '語文' then 1 when '數學' then 2 when '物理' then 3 when '平均分' then 4 when '總分' then 5 end



drop table tb



SQL code

create table #test (stunamem varchar(10),subject varchar(10),score int)

insert #test select '張三', '語文', 0

insert #test select '李四', '語文', 4

insert #test select '王二', '英文', 90

insert #test select '張三', '數學', 333







select stunamem,max(case when subject='語文' then score else 0 end)

,max(case when subject='英文' then score else 0 end)

,max(case when subject='數學' then score else 0 end)

from #test

group by stunamem

stunamem

---------- ----------- ----------- -----------

李四 4 0 0

王二 0 90 0

張三 0 0 333



(3 行受影響)



如果是2005的話,可以使用pivot函式。
SQL code



,[1996],[1997],[1998]

FROM dbo.Orders

PIVOT (

SUM(Quantity)

FOR [Year] IN ([1996],[1997],[1998])

)x

--結果:

CustomerID 1996 1997 1998

---------- ----------- ----------- -----------

ANTON 24 295 40

BONAP 181 486 313

BOTTM 81 454 421






更多請參考: SQL server 2005 PIVOT運算子的使用

[code=SQL]
USE   tempdb
GO
SELECT   YEAR(OrderDate)   AS   [Year]
              ,CustomerID  
              ,od.Quantity
INTO   dbo.Orders              
FROM   NorthWind..Orders   AS   o
        JOIN   NorthWind..[Order   Details]   AS   od
                ON   o.OrderID   =   od.OrderID
WHERE   o.CustomerID   IN   ( 'BONAP ', 'BOTTM ', 'ANTON ')

SELECT   CustomerID
,[1996],[1997],[1998]
FROM   dbo.Orders
PIVOT   (
      SUM(Quantity)
      FOR   [Year]   IN   ([1996],[1997],[1998])
      )x
   
--結果:    
CustomerID   1996                 1997                 1998
----------   -----------   -----------   -----------
ANTON             24                     295                   40
BONAP             181                   486                   313
BOTTM             81                     454                   421


[/code]

原文blog:http://www.cnblogs.com/www56/archive/2010/11/06/1870576.html