sql server 列值转列名的问题

目前在做相关数据的对比分析功能模块时,需要使用sql server 的列值转列名,一次转换后的结果又不能满足预期的需求。

要实现的预期效果如下图:

code name 江北区2011年2月 江北区2011年3月 江北区2011年4月 渝中区2011年2月 渝中区2011年3月 渝中区2011年4月
03070101 原木1 50 50 50 60 60 60
03070102 原木2 40 40 40 50 50 50

一、准备测试数据

创建临时测试数据表以及向其插入数据的T-SQL脚本如下:

 

 1 IF OBJECT_ID(N'tempdb.db.#tblTestData', N'U') IS NOT NULL
 2 
 3 BEGIN
 4     DROP TABLE dbo.#tblTestData;
 5 END
 6  
 7 -- 创建表
 8 CREATE TABLE dbo.#tblTestData
 9 (
10     [guid] VARCHAR(50) NOT NULL CONSTRAINT PK_U_CL_#tblTestData_guid PRIMARY KEY CLUSTERED,
11     code VARCHAR(50) NOT NULL,
12     [name] NVARCHAR(50) NOT NULL,
13     title NVARCHAR(50) NOT NULL,
14     area NVARCHAR(50) NOT NULL,
15     price FLOAT NOT NULL
16 );
17 GO
18  
19 -- 向其插入数据
20 INSERT INTO #tblTestData ([guid], code, [name], title, area, price) VALUES
21 (NEWID(), '03070101', N'原木1', N'2011年2月', N'江北区', 50),
22 (NEWID(), '03070102', N'原木2', N'2011年2月', N'江北区', 40),
23 (NEWID(), '03070101', N'原木1', N'2011年2月', N'渝中区', 60),
24 (NEWID(), '03070102', N'原木2', N'2011年2月', N'渝中区', 50),
25 (NEWID(), '03070101', N'原木1', N'2011年3月', N'江北区', 50),
26 (NEWID(), '03070102', N'原木2', N'2011年3月', N'江北区', 40),
27 (NEWID(), '03070101', N'原木1', N'2011年3月', N'渝中区', 60),
28 (NEWID(), '03070102', N'原木2', N'2011年3月', N'渝中区', 50),
29 (NEWID(), '03070101', N'原木1', N'2011年4月', N'江北区', 50),
30 (NEWID(), '03070102', N'原木2', N'2011年4月', N'江北区', 40),
31 (NEWID(), '03070101', N'原木1', N'2011年4月', N'渝中区', 60),
32 (NEWID(), '03070102', N'原木2', N'2011年4月', N'渝中区', 50);
33 GO

 执行以下查询T-SQL语句:

 

1 SELECT [guid], code, [name], title, area, price
2 FROM #tblTestData;
3 GO

 

得到如下结果:

 

二、解决问题的方案

以前解决方案:使用传统的基于CASE WHEN和动态SQL语句。

该方案分步骤实现如下:

1)、title列值转化为title列名的T-SQL代码如下: 

 1 DECLARE @chvnTSQL AS NVARCHAR(MAX) = N'';
 2 SET @chvnTSQL = N'SELECT code,[name],area';
 3  
 4 SELECT  @chvnTSQL = @chvnTSQL + N',MAX(CASE title WHEN ''' + title + ''' THEN price ELSE 0 END) AS [' + title + ']'
 5 FROM    (
 6          SELECT DISTINCT
 7                 title
 8          FROM   #tblTestData
 9         ) AS ExtendedColumnTable; /*-把所有唯一Title列出来*/
10  
11 SELECT  @chvnTSQL = @chvnTSQL + N'FROM #tblTestData GROUP BY code, [name], area ORDER BY code ASC';
12  
13 PRINT @chvnTSQL;
14 EXEC (@chvnTSQL);
15 GO

 执行后的结果如下:

 
 
2)、area列值转化为area列名T-SQL代码如下:
 1 DECLARE @chvnTSQL AS NVARCHAR(MAX) = N'';
 2  
 3 SET @chvnTSQL = N'SELECT code, [name], title';
 4  
 5 SELECT  @chvnTSQL = @chvnTSQL + N',SUM(CASE area WHEN ''' + area + ''' THEN price ELSE 0 END) AS [' + area + ']'
 6 FROM    (
 7          SELECT DISTINCT
 8                 area
 9          FROM   #tblTestData
10         ) AS bm; /*把所有唯一Title列出来*/
11 SELECT  @chvnTSQL = @chvnTSQL + N'FROM #tblTestData GROUP BY Code, [name], title ORDER BY code';
12  
13 PRINT @chvnTSQL;
14 EXEC (@chvnTSQL);
15 GO

执行后的结果如下:

 

针对以上2个步骤的执行结果来看,更难实现如文中开头部分的效果的。发现此方案对于我来说难解决该问题问题(目前我是没有发现,园中的博友如有解决方案,也请不吝赐教。)。

 

现在解决方案:和以前解决方案使用相同的技术,同样基于CASE WHEN和动态语句。

    该方案中最大不同就是将源表中area和title两个字段进行连接组合新的字段,使用一个临时中间数据表来保存对源表处理后得结果集。

    以下是临时中间表创建以及向其插入数据的T-SQL: 

 1 IF OBJECT_ID(N'tempdb.dbo.#tmpMiddleTable', N'U') IS NOT NULL
 2 BEGIN
 3     DROP TABLE dbo.#tmpMiddleTable;
 4 END
 5 --创建表
 6 CREATE TABLE #tmpMiddleTable (
 7     [guid] VARCHAR(50) NOT NULL CONSTRAINT PK_U_CL_tmpMiddleTable_guid PRIMARY KEY CLUSTERED,
 8     [name] NVARCHAR(50) NOT NULL,
 9     areatitle NVARCHAR(100) NOT NULL,
10     price FLOAT NOT NULL
11 );
12 GO
13  
14 -- 向其插入数据
15 INSERT INTO #tmpMiddleTable ([guid], name, areatitle, price)
16 SELECT [guid], name, CONCAT(area, title) AS areatitle, price
17 FROM #TempTest;
18 GO

 针对临时中间表来实现的T-SQL语句如下:

 1 DECLARE @chvnTSQL AS NVARCHAR(MAX) = N'';
 2  -- 给临时变量赋予默认值(SQL Server 2008才提供的这种功能
 3 SET @chvnTSQL = 'SELECT [name]';
 4  
 5 SELECT  @chvnTSQL = @chvnTSQL + ',MAX(CASE areatitle WHEN ''' + areatitle + ''' THEN price ELSE 0 END) AS [' + areatitle + ']'
 6 FROM    (
 7          SELECT DISTINCT
 8                 areatitle
 9          FROM   #tblMiddleTable
10         ) AS ExtendedColumnTable; /*把所有唯一Title列出来*/
11 --PRINT @chvnTSQL;
12 SELECT  @chvnTSQL = @chvnTSQL + 'FROM #tblMiddleTable GROUP BY [name]';
13  
14 PRINT @chvnTSQL;
15 EXEC (@chvnTSQL);
16 GO

执行后的结果如下: 

  
 
其他博友如果其他的解决方案,也请不吝赐教,万分谢谢。
posted @ 2011-11-02 10:19  剑走江湖  阅读(3809)  评论(0编辑  收藏  举报