T-SQL Enhancement in SQL Server 2005[下篇]
三、 PIVOT Operator
PIVOT的中文意思是“在枢轴上转动”,比如对于一个2维坐标,将横坐标变成纵坐标,将纵坐标变成横坐标。反映在一个Relational Table上的意思就是:变成为列,变列为行。相信大家在进行报表设计的时候都遇到过类似于这样的需求:统计2002年内某个销售人员第一季度每个月处理的订单数。在AdventureWorks Sample Databse中,Sales Order存储于SaleOrderHeader这张表中,它的结果如下:
我们一般情况下通过下面的SQL实现我们提出的统计功能:
SUM(CASE DATEPART(MM,OrderDate)WHEN 1 THEN 1 ELSE 0 END) AS JAN,
SUM(CASE DATEPART(MM,OrderDate)WHEN 2 THEN 1 ELSE 0 END) AS FEB,
SUM(CASE DATEPART(MM,OrderDate)WHEN 3 THEN 1 ELSE 0 END) AS MAR,
SUM(CASE DATEPART(MM,OrderDate)WHEN 4 THEN 1 ELSE 0 END) AS APR
FROM Sales.SalesOrderHeader
WHERE DATEPART(yyyy,OrderDate) = 2002
GROUP BY SalesPersonID
于是我们得到了这样的统计数据:
通过数据在原表的结构和我们最终获得的结果进行比较,我们发现就像是“旋转”了90度,原来的OrderDate是存储在每行的基于Order的一个属性(行),现在我们要把Order Date按照不同月份统计,这样行变成了列。
像这样的需求,我们都可以可以通过PIVOT这个操作符来实现,下面就是基于PIVOT的SQL:
FROM
(
SELECT SalesPersonID, DATEPART(MM,OrderDate) AS MON
FROM Sales.SalesOrderHeader
WHERE DATEPART(yyyy,OrderDate) = 2002
) S
PIVOT
(
COUNT(MON) FOR MON IN ([1],[2],[3],[4])
)
AS P
在上面的例子中,同过下面的SELECT语句筛选出来的是为经过PIVOT的数据。
FROM Sales.SalesOrderHeader
WHERE DATEPART(yyyy,OrderDate) = 2002
通过下面的PIVOT(COUNT(MON)是我们需要统计的数据,FOR MON IN ([1],[2],[3],[4]是统计的范围)就成了我们最终输出的结构了。
(
COUNT(MON) FOR MON IN ([1],[2],[3],[4])
)
如果你第一次见到PIVOT,可以不能一下明白它的实现,但是只要你是使用了一两次,相信就会很容易地掌握它。与PIVOT对应的还以一个操作符UNPIVOT,它完成PIVOT的逆操作,在这里就不介绍了,如果有兴趣的话,可以参考SQL Server Books Online。
四、 Ranking
排序与排名是我们最为常用的统计方式,比如对班级的学生根据成员进行排名,或者按照成绩高低把学生划分成若干梯队:比如最好成绩的10名学生属于第一梯队,后10名又划分为第二梯队,以此类推。Ranking设计的Key Words包括:ROW_NUMBER(),RANK(),DENSE_RANK(),NTILE()。我们现在就来介绍一下他们的用法和相互之间的差异。
1. 1. ROW_NUMBER()
看到ROW_NUMBER(),我想绝大多数人会像想到Oracle的ROWNUM。他们的作用相似,都是表示某条记录所处的Index。ROW_NUMBER()比Oracle的ROWNUM更加强大的是,它可以通过OVER语句指定一个进行排序的Column,比如:ROW_NUMBER() OVER (ORDER BY CustomerID)。
我们来看一个例子:对Sales.SalesOrderHeader按照CustomerID进行排序,并显示每条记录的Row Number。
FROM Sales.SalesOrderHeader
下面是查询结果:
我们发现最终的结果按照CutomerID进行排序,RowNum从1开始以此递增,每条记录(不管是否具有相同的CustomerID)拥有不同的RowNum。
提到排序,我们就不得不提到Order BY,如果我们在后面加上ORDER BY,并指定不同的排序字段,会出现怎样的结果呢?
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID
查询获得的结果是:
从上图中可以看到,最终的结果以ORDER BY中指定的SalesOrderID进行排序,但是ROW_NUMBER()体现的值却是基于CustmerID排序的。
由于ROW_NUMBER()体现是基于某个确定的字段进行排序后某个DataRow所处的位置,所以它不能直接使用到Aggregate的Column中。比如下面的SQL是不合法的:
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
要是想按照OrderCount,可以使用第一部分介绍的CTE:
AS
(
SELECT CustomerID,COUNT(*) AS OrderCount
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
)
SELECT CustomerID,OrderCount,ROW_NUMBER() OVER (ORDER BY OrderCount)
FROM CTE_Order
2. RANK()
RANK()的使用和ROW_NUMBER()类似。不过它与ROW_NUMBER()所不同的是:对于被指定为排序的字段,具有相同值得Row对应的返回值相同。比如:
FROM Sales.SalesOrderHeader
下面是相应的查询结果:
对于RANK(),还有一点需要说明的是,它的回返值不是连续的, 比如第五条记录的Row_Num是5而不是2。如果想实现这样需求,就需要用下面一个Function:DENSE_RANK()。
3. 3. DENSE_RANK()
DENSE_RANK()实现了一个连续的Ranking。比如下面的SQL:
FROM Sales.SalesOrderHeader
就来产生如下的查询结果:
4. NTILE()
上面我们说到划分梯队的问题,这样的问题可以通过NTILE() Function来实现。比如我们现在按照CustomerID排序,把CustomerID为1和2的划分到3梯队中:
FROM Sales.SalesOrderHeader
WHERE CustomerID <3
其查询结果为:
我们可以看到,一共12条记录,划分为3组,平均下来每组4条记录。
5. 5.PARTITION BY
上面提到的所有Ranking都是基于真个结果基的。而有的时候我们需要将真个结果集按照某个Column 进行分组,进行基于组的Ranking。这就需要PARTITION BY了。PARTITION BY置于OVER Clause中,和ORDER BY 平级。
比如下面的SQL将Order记录按照CustomerID进行分组,在每组中输出排名(安OrderDate排序):
FROM Sales.SalesOrderHeader
相应的查询结果:
T-SQL Enhancement in SQL Server 2005:
[原创]T-SQL Enhancement in SQL Server 2005 - Part I
[原创]T-SQL Enhancement in SQL Server 2005 - Part II
Reference: 《Programming Microsoft SQL Server 2005》 By Andrew J. Brust & Stephen Forte
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
T-SQL Enhancement in SQL Server 2005[下篇]相关推荐
- T-SQL Enhancement in SQL Server 2005[上篇]
较之前一版本,SQL Server 2005可以说是作出了根本性的革新.对于一般的编程人员来说,最具吸引力的一大特性就是实现了对CLR的寄宿,使我们可以使用任意一种.NET Programming L ...
- 在SQL Server 2000 和SQL Server 2005中导出表结构
SQL Server 2000 SELECT 表名 = case when a.colorder=1 then d.name else '' end, 表说明 = ...
- 如何 SQL Server 2005 实例之间传输登录和密码
INTRODUCTION 本文介绍如何不同服务器上的 Microsoft SQL Server 2005 实例之间传输登录和密码. 本文, 服务器 A 和服务器 B 是不同的服务器. 此外, 服务器 ...
- SQL Server 2005下的分页SQL
其实基本上有三种方法: 1.使用SQL Server 2005中新增的ROW_NUMBER 几种写法分别如下: 1SELECT TOP 20 * FROM (SELECT 2 ROW_NUMBER ...
- 如何使用 DBCC MEMORYSTATUS 命令来监视 SQL Server 2005 中的内存使用情况
https://technet.microsoft.com/en-us/solutionaccelerators/dd537566.aspx 注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完 ...
- 数据库开发基本操作-安装Sql Server 2005出现“性能监视器计数器要求”错误解决方法...
今天在安装SQL Server 2005时,出现"性能监视器计数器要求"错误,因为以前出现过这种错误,得到了解决.今天又又出现这种错误,但并不是很清楚当时的解决办法,所以这次把解决 ...
- 数据库开发基本操作-关于sql server 2005 未开放1433端口的问题
有些sql server 2005在安装过程中,可能将SQL server 服务的端口配置成了动态端口,没有使用默认的1433端口,从而导致了sql server 2005 的服务启动了,但是却没有开 ...
- ASP.NET 2.0在SQL Server 2005上自定义分页
这篇文章讲述了如何利用SQL Server 2005的新特性来简单高效的实现分页.对于那些暂时还没用到SQL Server2005的人们,请看在大规模数据中的高效分页方法.如果需要,这篇文章会补上这里 ...
- SQL Server 2005/2008 用户数据库文件默认路径和默认备份路径修改方法
2019独角兽企业重金招聘Python工程师标准>>> 一直想把数据库的默认路径修改一下,在网上找了一下,真的发现有办法 , 特拿 来与大家共同分享. 以下仅为参照,如果有多个实例, ...
最新文章
- java 注解类说明
- mysql单机多实例启动不了_mysql单机启用多实例的配置方法
- java源码-AQS机制
- Oracle 存储过程的导出导入序列的导出
- windows和linux共同分区格式,Linux和Windows共存的模式下分区要小心
- JAVA就业面试题之单例模式
- 利用UDEV服务解决RAC ASM存储设备名
- oracle中v$database视图详解
- 异步复位设计中的亚稳态问题及其解决方案
- %3c php foreach%3e,PHP 数组函数-数组排序
- spring boot 调试 - 热部署
- iOS9 访问http网络
- 关系数据库设计理论--3NF
- undefined: resolver.BuildOption
- 上新:视频加密功能增加防录屏(随机水印)功能
- UART子系统(五) 串口应用编程之回环
- stylus -w style.styl -o style.css
- 聚集索引与非聚集索引的区别
- 大学英语六级考试题型分值分配、时间分配、做题策略
- MathType如何编辑大三角形符号