程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> SQL Server 特殊需要的行轉列

SQL Server 特殊需要的行轉列

編輯:關於SqlServer
一、數據庫SQL Server行轉列 需求:原始表的數據的結構如圖1所示,把相同的guid的code值轉換為列值。
  (圖1) 目標:我們希望達到的效果如圖2所示,這裡的guid變成唯一的了,這行的記錄中包含了這個guid所對應的code字段值。
  (圖2) 分析與實現:要實現圖1到圖2的轉變,這就是所謂的行轉列,下面我們來講講具體的實現: 1.         首先我們先創建一個測試表,方便後面的效果展現; --創建表
if exists (select * from sysobjects where id = OBJECT_ID('[TempTable_Base]') and OBJECTPROPERTY(id, 'IsUserTable') = 1) 
DROP TABLE [TempTable_Base]

CREATE TABLE [TempTable_Base] (
[id] [int]  IDENTITY (1, 1)  NOT NULL,
[guid] [varchar]  (50) NULL,
[code] [varchar]  (50) NULL)

SET IDENTITY_INSERT [TempTable_Base] ON

INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 1,'91E92DCB-141A-30B2-E6CD-B59EABD21749','A')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 2,'91E92DCB-141A-30B2-E6CD-B59EABD21749','C')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 3,'91E92DCB-141A-30B2-E6CD-B59EABD21749','E')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 4,'91E92DCB-141A-30B2-E6CD-B59EABD21749','O')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 5,'91E92DCB-141A-30B2-E6CD-B59EABD21749','G')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 6,'79DD7AB9-CE57-9431-B020-DF99731FC99D','A')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 7,'79DD7AB9-CE57-9431-B020-DF99731FC99D','O')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 8,'79DD7AB9-CE57-9431-B020-DF99731FC99D','E')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 9,'79DD7AB9-CE57-9431-B020-DF99731FC99D','F')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 10,'79DD7AB9-CE57-9431-B020-DF99731FC99D','O')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 11,'79DD7AB9-CE57-9431-B020-DF99731FC99D','B')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 12,'79DD7AB9-CE57-9431-B020-DF99731FC99D','D')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 13,'79DD7AB9-CE57-9431-B020-DF99731FC99D','F')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 14,'D61651D9-1B0A-0362-EE91-A805AA3E08F2','O')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 15,'D61651D9-1B0A-0362-EE91-A805AA3E08F2','D')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 16,'D61651D9-1B0A-0362-EE91-A805AA3E08F2','F')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 17,'D61651D9-1B0A-0362-EE91-A805AA3E08F2','C')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 18,'D61651D9-1B0A-0362-EE91-A805AA3E08F2','U')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 19,'D61651D9-1B0A-0362-EE91-A805AA3E08F2','F')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 20,'4802F0CD-B53F-A3F5-1C78-2D7424579C06','A')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 21,'3CCBFF9F-827B-6639-4780-DA7215166728','O')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 22,'3CCBFF9F-827B-6639-4780-DA7215166728','M')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 23,'3CCBFF9F-827B-6639-4780-DA7215166728','C')
INSERT [TempTable_Base] ([id],[guid],[code]) VALUES ( 24,'3CCBFF9F-827B-6639-4780-DA7215166728','M')

SET IDENTITY_INSERT [TempTable_Base] OFF

SELECT * FROM [TempTable_Base]
  2.         使用SQL Server2005的row_number()函數來進行分組排名,把同一個guid的數據進行標識,這樣就可以讓不同的guid具有數字1以後的數值,這樣就可以作為新的列名來進行行轉列了,執行下面的SQL就可以達到圖3所示的效果了。  --對數據進行分組
select base.*,row_number() over (partition by guid order by ID) as depth 
from [TempTable_Base] as base
order by id
  (圖3)   3.         生成分組表,把上面的結構插入到一張新的表中,把數據保存為一個表是為了方便後面的統計使用。  --生成分組表
select base.*,row_number() over (partition by guid order by ID) as depth 
into [TempTable_Depth]
from [TempTable_Base] as base
order by id

SELECT * FROM [TempTable_Depth]
  4.         動態行轉列的SQL,因為你不知道列數據會有多少,所以我們使用下面的SQL來動態的生成列名,結果就如圖2所示。 --行轉列
declare @s nvarchar(max)
set @s=''
Select @s=@s+','+quotename([depth])+'=max(case when [depth]='+quotename([depth],'''')+' then code else null end)'
from [TempTable_Depth] group by [depth] order by [depth]
exec('select guid '+@s+' from [TempTable_Depth] group by guid order by guid')
    二、數據庫SQL Server生成矩陣數據 需求:我們回過頭來看看圖1,比如guid為91E92DCB-141A-30B2-E6CD-B59EABD21749的code值包括A,C,E,O,G這五個,我們可以想象guid為一個用戶,這五個code就是這個用戶訪問網站頁面的順序,那如果我想看到一個從A->C,C-> E,E-> O,O -> G這個矩陣中兩兩對應在數據庫中出現了多少次?   目標:我們希望達到的效果如圖4所示,這個圖可以解讀為A->A的個數是0,A->C的個數是1,D->F的個數是2,這些統計方法可能會在一些需要進行對比分析的過程中用到。
  (圖4) 分析與實現:要實現圖4的效果,這就需要我們對數據進行矩陣轉換,下面我們來講講具體的實現: 1.         首先我們需要巧用left join和depth字段,depth就相當於用戶訪問的順序,所以我們可以把之前有序的拷貝一份到右邊去,效果如圖5所示。 --巧用左連接和depth字段進行處理
select a.id,a.guid,a.code as code_from,b.code as code_to 
from [TempTable_Depth] as a
left join [TempTable_Depth] as b
on a.guid = b.guid and a.[depth] = b.[depth]-1
  (圖5)   2.         為了方便統計,把上面的成果保存到一個表中,之後就是為所有唯一的code值生成一個以code作為元素的二維矩陣的原始數據,它就相當於一個臨時表一樣,用來保存每一個code對應的個數,效果如圖6所示。  --生成From和To的對應關系
select a.id,a.guid,a.code as code_from,b.code as code_to 
into [TempTable_FromTo]
from [TempTable_Depth] as a
left join [TempTable_Depth] as b
on a.guid = b.guid and a.[depth] = b.[depth]-1


--生成矩陣
select distinct code_from ,1 as num
into [TempTable_t1]
from [TempTable_FromTo]
order by code_from

select * from [TempTable_t1]

--生成一個矩陣表
select a.code_from ,b.code_from as code_to,0 as counts  
into [TempTable_t2]
from [TempTable_t1] as a
left join [TempTable_t1] as b
on a.num = b.num
order by a.code_from ,b.code_from

select * from [TempTable_t2]
  (圖6)   3.         現在就需要把統計的A->A這樣數據的個數,並把它放入圖6中的表中,效果如圖7所示。  --統計
select code_from ,code_to, count(1) as counts
into [TempTable_t3]
from [TempTable_FromTo]
where code_to is not null
group by code_from ,code_to--,guid
order by code_from ,code_to

select * from [TempTable_t3]


--更新統計的數字
update a set a.counts = b.counts
from [TempTable_t2] as a,[TempTable_t3] as b
where a.code_from = b.code_from 
and a.code_to = b.code_to
and b.counts is not null

select * from [TempTable_t2]
  (圖7)   4.         現在需要做的就是把行轉列了,這也沒有違背我們的標題啊,呵呵,效果如圖8所示。  --查詢矩陣
declare @s nvarchar(max)
set @s=''
Select @s=@s+','+quotename([code_to])+'=max(case when [code_to]='+quotename([code_to],'''')+' then counts else null end)'
from [TempTable_t2] group by [code_to] order by [code_to]
exec('select [code_from] '+@s+' from [TempTable_t2] group by [code_from] order by [code_from]')


  (圖8)   總結:其實這篇文章我想表達正是這個矩陣的生成方法,在現實中也許並不常用到,但是還是有些技巧性的東西在裡面,比如那個dept的用處;再比如a.[depth] = b.[depth]-1這個SQL的巧用;再比如行轉列解決矩陣問題;還有動態生成行轉列的SQL,其實這裡還可以使用SQL Server 2005的pivot來解決行轉列的問題,這裡就不列出來了。希望這篇文章能給你遇到的問題帶來一些幫助和啟示。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved