[SQL] 普通行列转换(version 2.0) →→→→→进入此内容的聊天室

来自 , 2019-05-25, 写在 SQL, 查看 131 次.
URL http://www.code666.cn/view/5faf461e
  1. 说明:普通行列转换(version 1.0)仅针对SQL server 2000提供静态和动态写法,version 2.0增加SQL server 2005的有关写法。
  2.  
  3. 问题:假设有张学生成绩表(tb)如下:
  4. 姓名 课程 分数
  5. 张三 语文 74
  6. 张三 数学 83
  7. 张三 物理 93
  8. 李四 语文 74
  9. 李四 数学 84
  10. 李四 物理 94
  11. 想变成(得到如下结果)
  12. 姓名 语文 数学 物理
  13. ---- ---- ---- ----
  14. 李四 74 84 94
  15. 张三 74 83 93
  16. -------------------
  17. */
  18.  
  19. CREATE TABLE tb(姓名 VARCHAR(10) , 课程 VARCHAR(10) , 分数 INT)
  20. INSERT INTO tb VALUES('张三' , '语文' , 74)
  21. INSERT INTO tb VALUES('张三' , '数学' , 83)
  22. INSERT INTO tb VALUES('张三' , '物理' , 93)
  23. INSERT INTO tb VALUES('李四' , '语文' , 74)
  24. INSERT INTO tb VALUES('李四' , '数学' , 84)
  25. INSERT INTO tb VALUES('李四' , '物理' , 94)
  26. GO
  27.  
  28. --SQL SERVER 2000 静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)
  29. SELECT 姓名 AS 姓名 ,
  30. MAX(CASE 课程 WHEN '语文' THEN 分数 ELSE 0 END) 语文,
  31. MAX(CASE 课程 WHEN '数学' THEN 分数 ELSE 0 END) 数学,
  32. MAX(CASE 课程 WHEN '物理' THEN 分数 ELSE 0 END) 物理
  33. FROM tb
  34. GROUP BY 姓名
  35.  
  36. --SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
  37. DECLARE @SQL VARCHAR(8000)
  38. SET @SQL = 'select 姓名 '
  39. SELECT @SQL = @SQL + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
  40. FROM (SELECT DISTINCT 课程 FROM tb) AS a
  41. SET @SQL = @SQL + ' from tb group by 姓名'
  42. EXEC(@SQL)
  43.  
  44. --SQL SERVER 2005 静态SQL。
  45. SELECT * FROM (SELECT * FROM tb) a pivot (MAX(分数) FOR 课程 IN (语文,数学,物理)) b
  46.  
  47. --SQL SERVER 2005 动态SQL。
  48. DECLARE @SQL VARCHAR(8000)
  49. SELECT @SQL = isnull(@SQL + '],[' , '') + 课程 FROM tb GROUP BY 课程
  50. SET @SQL = '[' + @SQL + ']'
  51. EXEC ('select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @SQL + ')) b')
  52.  
  53. ---------------------------------
  54.  
  55. /*
  56. 问题:在上述结果的基础上加平均分,总分,得到如下结果:
  57. 姓名 语文 数学 物理 平均分 总分
  58. ---- ---- ---- ---- ------ ----
  59. 李四 74 84 94 84.00 252
  60. 张三 74 83 93 83.33 250
  61. */
  62.  
  63. --SQL SERVER 2000 静态SQL。
  64. SELECT 姓名 姓名,
  65. MAX(CASE 课程 WHEN '语文' THEN 分数 ELSE 0 END) 语文,
  66. MAX(CASE 课程 WHEN '数学' THEN 分数 ELSE 0 END) 数学,
  67. MAX(CASE 课程 WHEN '物理' THEN 分数 ELSE 0 END) 物理,
  68. CAST(avg(分数*1.0) AS DECIMAL(18,2)) 平均分,
  69. SUM(分数) 总分
  70. FROM tb
  71. GROUP BY 姓名
  72.  
  73. --SQL SERVER 2000 动态SQL。
  74. DECLARE @SQL VARCHAR(8000)
  75. SET @SQL = 'select 姓名 '
  76. SELECT @SQL = @SQL + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
  77. FROM (SELECT DISTINCT 课程 FROM tb) AS a
  78. SET @SQL = @SQL + ' , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名'
  79. EXEC(@SQL)
  80.  
  81. --SQL SERVER 2005 静态SQL。
  82. SELECT m.* , n.平均分 , n.总分 FROM
  83. (SELECT * FROM (SELECT * FROM tb) a pivot (MAX(分数) FOR 课程 IN (语文,数学,物理)) b) m,
  84. (SELECT 姓名 , CAST(avg(分数*1.0) AS DECIMAL(18,2)) 平均分 , SUM(分数) 总分 FROM tb GROUP BY 姓名) n
  85. WHERE m.姓名 = n.姓名
  86.  
  87. --SQL SERVER 2005 动态SQL。
  88. DECLARE @SQL VARCHAR(8000)
  89. SELECT @SQL = isnull(@SQL + ',' , '') + 课程 FROM tb GROUP BY 课程
  90. EXEC ('select m.* , n.平均分 , n.总分 from
  91. (select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @SQL + ')) b) m ,
  92. (select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
  93. where m.姓名 = n.姓名')
  94.  
  95. DROP TABLE tb
  96.  
  97. ------------------
  98. ------------------
  99.  
  100. /*
  101. 问题:如果上述两表互相换一下:即表结构和数据为:
  102. 姓名 语文 数学 物理
  103. 张三 74  83  93
  104. 李四 74  84  94
  105. 想变成(得到如下结果):
  106. 姓名 课程 分数
  107. ---- ---- ----
  108. 李四 语文 74
  109. 李四 数学 84
  110. 李四 物理 94
  111. 张三 语文 74
  112. 张三 数学 83
  113. 张三 物理 93
  114. --------------
  115. */
  116.  
  117. CREATE TABLE tb(姓名 VARCHAR(10) , 语文 INT , 数学 INT , 物理 INT)
  118. INSERT INTO tb VALUES('张三',74,83,93)
  119. INSERT INTO tb VALUES('李四',74,84,94)
  120. GO
  121.  
  122. --SQL SERVER 2000 静态SQL。
  123. SELECT * FROM
  124. (
  125. SELECT 姓名 , 课程 = '语文' , 分数 = 语文 FROM tb
  126. UNION ALL
  127. SELECT 姓名 , 课程 = '数学' , 分数 = 数学 FROM tb
  128. UNION ALL
  129. SELECT 姓名 , 课程 = '物理' , 分数 = 物理 FROM tb
  130. ) t
  131. ORDER BY 姓名 , CASE 课程 WHEN '语文' THEN 1 WHEN '数学' THEN 2 WHEN '物理' THEN 3 END
  132.  
  133. --SQL SERVER 2000 动态SQL。
  134. --调用系统表动态生态。
  135. DECLARE @SQL VARCHAR(8000)
  136. SELECT @SQL = isnull(@SQL + ' union all ' , '' ) + ' select 姓名 , [课程] = ' + quotename(Name , '''') + ' , [分数] = ' + quotename(Name) + ' from tb'
  137. FROM syscolumns
  138. WHERE name! = N'姓名' AND ID = object_id('tb') --表名tb,不包含列名为姓名的其它列
  139. ORDER BY colid ASC
  140. EXEC(@SQL + ' order by 姓名 ')
  141.  
  142. --SQL SERVER 2005 动态SQL。
  143. SELECT 姓名 , 课程 , 分数 FROM tb unpivot (分数 FOR 课程 IN([语文] , [数学] , [物理])) t
  144.  
  145. --SQL SERVER 2005 动态SQL,同SQL SERVER 2000 动态SQL。
  146.  
  147. --------------------
  148. /*
  149. 问题:在上述的结果上加个平均分,总分,得到如下结果:
  150. 姓名 课程 分数
  151. ---- ------ ------
  152. 李四 语文 74.00
  153. 李四 数学 84.00
  154. 李四 物理 94.00
  155. 李四 平均分 84.00
  156. 李四 总分 252.00
  157. 张三 语文 74.00
  158. 张三 数学 83.00
  159. 张三 物理 93.00
  160. 张三 平均分 83.33
  161. 张三 总分 250.00
  162. ------------------
  163. */
  164.  
  165. SELECT * FROM
  166. (
  167. SELECT 姓名 AS 姓名 , 课程 = '语文' , 分数 = 语文 FROM tb
  168. UNION ALL
  169. SELECT 姓名 AS 姓名 , 课程 = '数学' , 分数 = 数学 FROM tb
  170. UNION ALL
  171. SELECT 姓名 AS 姓名 , 课程 = '物理' , 分数 = 物理 FROM tb
  172. UNION ALL
  173. SELECT 姓名 AS 姓名 , 课程 = '平均分' , 分数 = CAST((语文 + 数学 + 物理)*1.0/3 AS DECIMAL(18,2)) FROM tb
  174. UNION ALL
  175. SELECT 姓名 AS 姓名 , 课程 = '总分' , 分数 = 语文 + 数学 + 物理 FROM tb
  176. ) t
  177. ORDER BY 姓名 , CASE 课程 WHEN '语文' THEN 1 WHEN '数学' THEN 2 WHEN '物理' THEN 3 WHEN '平均分' THEN 4 WHEN '总分' THEN 5 END
  178.  
  179. DROP TABLE tb
  180.  
  181. //SQL/1209

回复 "普通行列转换(version 2.0)"

这儿你可以回复上面这条便签

captcha