表sales
年份 | 季度 | 金额 |
1991 | 1 | 11 |
1991 | 2 | 22 |
1991 | 3 | 33 |
1991 | 4 | 44 |
1992 | 1 | 55 |
1992 | 2 | 66 |
1992 | 3 | 77 |
1992 | 4 | 88 |
查询结果如下:
年份 | 第一季度 | 第二季度 | 第三季度 | 第四季度 |
1991 | 11 | 22 | 33 | 44 |
1992 | 55 | 66 | 77 | 88 |
请写出sql语句。
当我看到这样的问题时我的内心是崩溃的,一点思路都没有!回到家赶紧查上网查了一下,记录备忘。
建表:
CREATE TABLE [dbo].[sales]( [id] [int] IDENTITY(1,1) NOT NULL, [year] [int] NULL, [jidu] [int] NULL, [jine] [int] NULL, PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
有两种方法:
一、使用case when 实现:
SELECT year as '年份', max(CASE jidu WHEN 1 THEN jine END) AS '第一季度', max(CASE jidu WHEN 2 THEN jine END) AS '第二季度', max(CASE jidu WHEN 3 THEN jine END) AS '第三季度', max(CASE jidu WHEN 4 THEN jine END) AS '第四季度' FROM sales group by year
很容易理解,但写起来很麻烦。下面介绍下一种。
二、使用pivot函数:
使用pivot函数时须注意 对升级到 SQL Server 2005 或更高版本的数据库使用 PIVOT 和 UNPIVOT 时,必须将数据库的兼容级别设置为 90 或更高。
参考:
https://technet.microsoft.com/zh-cn/library/ms177410(v=sql.105).aspx
PIVOT 通过将表达式某一列中的唯一值转换为输出中的多个列来旋转表值表达式,并在必要时对最终输出中所需的任何其余列值执行聚合。
PIVOT的语法:
SELECT <非透视的列>,
[第一个透视的列] AS <列名称>,
[第二个透视的列] AS <列名称>,
...
[最后一个透视的列] AS <列名称>,
FROM
(<生成数据的 SELECT 查询>)
AS <源查询的别名>
PIVOT
(
<聚合函数>(<要聚合的列>)
FOR
[<包含要成为列标题的值的列>]
IN ( [第一个透视的列], [第二个透视的列],
... [最后一个透视的列])
) AS <透视表的别名>
<可选的 ORDER BY 子句>;
按照上述语法写出sql:
select year as 年份,[1] as 第一季度,[2] as 第二季度,[3] as 第三季度,[4] as 第四季度 from sales pivot (SUM(jine) FOR jidu IN ([1],[2],[3],[4]))a
看着就清秀,执行结果如下:
这是什么鬼……
其实很明显,分组出现了问题,但是按照语法 只能指定需要横向显示的列即聚合函数中的列和要成为列标题的值的列,不能明确定义分组列。用作分组的列是PIVOT函数中没有应用到的列(即 字段 id),会根据id和year两个字段分组。
注意源查询中是可以使用select语句的,PIVOT可以操作结果集,因此只需要将源查询中不显示id这个字段就可以了:
select year as 年份,[1] as 第一季度,[2] as 第二季度,[3] as 第三季度,[4] as 第四季度 from (select year,jidu,jine from sales) as t1 pivot (SUM(jine) FOR jidu IN ([1],[2],[3],[4])) as a --'t1'和'a'这两个别名必须得有要不会报错。
执行结果:
终于对了。