翔如菲菲

其实天很蓝,阴云总会散;其实海不宽,此岸连彼岸.

导航

SQL SERVER行转换列及PIVOT

--*****************SQL 行转列***************************
--创建实例表
IF OBJECT_ID('TB')IS NOT NULL
 DROP TABLE TB
GO
--构建实例数据
CREATE TABLE TB(姓名 NVARCHAR(10),课程 NVARCHAR(10),分数 INT)

INSERT INTO TB VALUES(N'张三',N'语文',74)

INSERT INTO TB VALUES(N'张三',N'数学',83)

INSERT INTO TB VALUES(N'张三',N'物理',93)

INSERT INTO TB VALUES(N'李四',N'语文',74)

INSERT INTO TB VALUES(N'李四',N'数学',84)

INSERT INTO TB VALUES(N'李四',N'物理',94)

SELECT * FROM TB WITH(NOLOCK)
GO
--***************行转列***************************
--实现课程列值旋转为列名
    --使用SQL SERVER 2000静态SQL
     SELECT 
         姓名
        ,MAX(CASE 课程 
             WHEN N'语文'  THEN 分数 
             ELSE 0 
         ENDAS N'语文' 
        ,MAX(CASE 课程 
             WHEN N'数学'  THEN 分数 
             ELSE 0 
         ENDAS N'数学' 
        ,MAX(CASE 课程 
             WHEN N'物理'  THEN 分数 
             ELSE 0 
         ENDAS N'物理'  
     FROM TB 
     GROUP BY 姓名
    --SQL SERVER 2000动态SQL,指课程不止语文、数学、物理这三门课程。
    --变量按SQL语言顺序赋值
    DECLARE @SQL1 NVARCHAR(MAX)

    SET @SQL1=N'SELECT 姓名'

    SELECT 
        @SQL1=@SQL1+N',MAX(CASE 课程 
            WHEN N
'''+课程+N''' THEN 分数 
            ELSE 0 
        END)[
'+课程+']'  
    FROM
            SELECT 
                DISTINCT 课程 
            FROM TB 
         )A  
    SET @SQL1=@SQL1+N' FROM TB GROUP BY 姓名'

    EXEC(@SQL1)
    --使用ISNULL(),变量先确定动态部分
    DECLARE @SQL NVARCHAR(MAX)
    SELECT 
        @SQL=ISNULL(@SQL+',',''+N' MAX(CASE 课程 
                WHEN N
'''+课程+ N''' THEN 分数 
                ELSE 0 
            END) [
'+课程+N']'  
    FROM(
            SELECT 
                DISTINCT 课程 
            FROM TB
         )AS A      
    SET @SQL=N'SELECT 
                   姓名,
'+@SQL+N' FROM TB GROUP BY 姓名'

    EXEC(@SQL)

    PIVOT--列值转换为列名,即行转列

    PIVOT(聚合函数(列) FOR 列 in (…) )AS P
    完整语法:
    Table_Source
    PIVOT
    (
    聚合函数【MAX,SUM,等】(value_column)
    FOR pivot_column【要成为列标题的值的列】
       IN(列值 of pivot_column)
    ) 别命
    --使用SQL SERVER 2005静态SQL
 SELECT 
     姓名
    ,语文
    ,数学
    ,物理 
 FROM TB 
 PIVOT
 ( 
      MAX(分数)FOR 课程 IN 
     ( 
          语文 
         ,数学 
         ,物理 
     ) 
 )A  
    --使用SQL Server 2005动态SQL
 --1使用STUFF( character_expression , start , length ,character_expression ),start 从索引1开始
    DECLARE @SQL2 NVARCHAR(MAX)
    SET  @SQL2=''  
    SELECT  @SQL2= @SQL2+','+课程 FROM TB GROUP BY 课程 
    PRINT @SQL2
    SET @SQL2=STUFF@SQL2,1,1,'')--去掉首个','
    PRINT @SQL2
    SET @SQL2=N'SELECT * FROM TB PIVOT (MAX(分数) FOR 课程 IN ('+ @SQL2+'))A'
    EXEC@SQL2)

    --2使用ISNULL()
    DECLARE  @SQL3 NVARCHAR(MAX)
    SELECT  @SQL3=ISNULL@SQL3+',','')+课程 FROM TB GROUP BY 课程           
    SET @SQL3=N'SELECT * FROM TB PIVOT (MAX(分数) FOR 课程 IN ('+ @SQL3+'))A'
    EXEC@SQL3)

/*运行结果:
    姓名       语文        数学        物理
    ---------- ----------- ----------- -----------
    张三       74          83          93
    李四       74          84          94
*/

--行转列结果加上总分、平均分
    --SQL SERVER 2000静态SQL
    BEGIN
        SELECT 
            姓名 
           ,MAX(CASE 课程 
                WHEN N'语文'  THEN 分数 
                ELSE 0 
            END) 数学 
           ,MAX(CASE 课程 
                WHEN N'数学'  THEN 分数 
                ELSE 0 
            END) 物理 
           ,MAX(CASE 课程 
                WHEN N'物理'  THEN 分数 
                ELSE 0 
            END) 语文 
           ,SUM(分数) AS 总分
           ,CAST(AVG(分数*1.0AS DECIMAL(4,2)) AS 平均分
        FROM TB 
        GROUP BY 姓名
    END

    --SQL SERVER 2000动态SQL
    BEGIN
        DECLARE @SQL4 nvarchar(MAX)
        SELECT 
            @SQL4=ISNULL(@SQL4+',','')+N' MAX(CASE 课程 WHEN N'''+课程+N''' THEN 分数 ELSE 0 END)' +课程
        FROM (SELECT 
                  DISTINCT  课程
              FROM TB 
           ) AS TT
         SET @SQL4=N'SELECT 
                         姓名
                        ,
'+@SQL4++N',SUM(分数)AS 总分
                        ,CAST(AVG(分数*1.0)AS decimal(4,2)) AS 平均分 
                     FROM TB 
                     GROUP BY 姓名
'
        PRINT @SQL4
        EXEC(@sql4)
    END
    --SQL SERVER 2005 静态PIVOT
    BEGIN
        SELECT 
            A.*
           ,B.总分
           ,B.平均分 
        FROM (
                SELECT 
                    * 
                FROM TB 
                PIVOT
                ( 
                     MAX(分数) FOR 课程 IN 
                    ( 
                         数学 
                        ,语文 
                        ,物理 
                    ) 
                ) AS TT
             ) AS A 
        INNER JOIN (
            SELECT 
                姓名
               ,SUM(分数) AS 总分 
               ,CAST(AVG(分数*1.0AS decimal(4,2)) AS 平均分 
            FROM TB 
            GROUP BY 姓名
         ) AS B 
            ON A.姓名=B.姓名
    END
    --SQL SERVER 2005 动态PIVOT
    BEGIN
        DECLARE @SQL5 NVARCHAR(MAX)
        SELECT 
            @SQL5=ISNULL(@SQL5+ ',','')+ 课程 
        FROM TB  
        GROUP BY 课程
        SET @SQL5=N'SELECT * FROM TB PIVOT (MAX(分数) FOR 课程 IN ('+@SQL5+')) AS TT'
        SET @SQL5=N'SELECT A.*,B.总分,B.平均分 FROM ('+@SQL5+N') AS A 
        INNER JOIN (SELECT 姓名,SUM(分数) AS 总分,CAST(AVG(分数) AS DECIMAL(4,2)) AS 平均分 FROM TB GROUP BY 姓名) AS B 
        ON A.姓名=B.姓名
'
                PRINT @SQL5
        EXEC SP_EXECUTESQL @SQL5
    END
/*运行结果:
    姓名  语文 数学 物理 总分  平均分
    ----------------- ----------- ----
    李四  74   84   94   252   84.00
    张三  74   83   93   250   83.33
*/

 

--另一个例子
--Create 样例表
IF OBJECT_ID('TEST'IS NOT NULL
BEGIN
    DROP TABLE TEST
END

CREATE TABLE TEST
(
     ID INT
    ,Name VARCHAR(20)
    ,[Quarter] INT
    ,[Profile] INT
)
--构建样例数据
INSERT INTO TEST VALUES(1,'A',1,1000)
INSERT INTO TEST VALUES(1,'A',2,2000)
INSERT INTO TEST VALUES(1,'A',3,4000)
INSERT INTO TEST VALUES(1,'A',4,5000)
INSERT INTO TEST VALUES(1,'B',1,3000)
INSERT INTO TEST VALUES(1,'B',2,3500)
INSERT INTO TEST VALUES(1,'B',3,4200)
INSERT INTO TEST VALUES(1,'B',4,5500)
--行转换列:四个季度的利润转换成横向显示
--SQL SERVER 2000 静态SQL
SELECT 
    ID 
   ,Name 
    ,SUM(CASE [Quarter] 
        WHEN 1 THEN [Profile]
        ELSE 0 
    ENDAS N'1季度' 
    ,SUM(CASE [Quarter] 
            WHEN 2 THEN [Profile]
            ELSE 0 
        ENDAS N'2季度' 
    ,SUM(CASE [Quarter] 
            WHEN 3 THEN [Profile]
            ELSE 0 
        ENDAS N'3季度' 
    ,SUM(CASE [Quarter] 
            WHEN 4 THEN [Profile]
            ELSE 0 
        ENDAS N'4季度' 
FROM TEST 
GROUP BY ID,Name
--SQL SERVER 2005 静态PIVOT
SELECT 
   *
FROM TEST 
PIVOT
(
     SUM([Profile]FOR [Quarter] IN ([1],[2],[3],[4])
AS TT


posted on 2011-03-24 11:21  翔如飞飞  阅读(403)  评论(0编辑  收藏  举报