《SQL Server 2012 T-SQL基础》读书笔记 - 7.进阶查询
Chapter 7 Beyond the Fundamentals of Querying
window function是什么呢?就是你SELECT出来一个结果集,然后对于每一行,你都想给它对应一个标量(a scalar),而这个标量是通过a subset of rows计算得到的,而这个a subset of the rows其实就是你得到的结果集里面的一个subset(子集)。所以说就是把每一行都对应a subset of the rows,而这个对应关系通过OVER指定。举个例子:
SELECT empid, ordermonth, val,
SUM(val) OVER(PARTITION BY empid
ORDER BY ordermonth
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) AS runval
FROM Sales.EmpOrders;
结果:
讲解一下。OVER子句里面有三个部分:partitioning, ordering, and framing。partitioning就是PARTITION BY,其实就是分组,类似GROUP BY,如果不指定PARTITION BY,那么每行的对应就是整个结果集。ordering对应ORDER BY,但这里的ORDER BY跟数据展示没关系,它只是为了这个window函数服务的,也就是有些具体的计算需要根据顺序来计算。最后的ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW对应framing,UNBOUNDED PRECEDING表示分组的开始。所以说,比如对于上面的empid = 1的那几行,runval是根据ordermonth不断累积的。
Ranking Window Functions:
SELECT orderid, custid, val,
ROW_NUMBER() OVER(ORDER BY val) AS rownum,
RANK() OVER(ORDER BY val) AS rank,
DENSE_RANK() OVER(ORDER BY val) AS dense_rank,
NTILE(10) OVER(ORDER BY val) AS ntile
FROM Sales.OrderValues
ORDER BY val;
结果:
注意上面的val列里面有两行都为36,那么这时候ROW_NUMBER会给他们分配不同的编号。但是RANK和DENSE_RANK会给他们分配相同的编号,rank编号为9的意思是有8行的val比这行的val要小,dense rank为9的意思是有distinct的8行的val比这行的val要小。
NTILE(10)意思就是把结果分成十组,因为一共有830行,所以每组有83行。
注意,SELECT中如果用了DISTINCT,那么DISTINCT是在window函数之后进行的,如果你同时用了DISTINCT和ROW_NUMBER,那么你还不如不要这个DISTINCT。
Offset Window Functions:
先举个栗子:
SELECT custid, orderid, val,
LAG(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid) AS prevval,
LEAD(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid) AS nextval
FROM Sales.OrderValues;
结果:
讲解一下:PARTITION BY custid就相当于把范围定在custid是一样的这些行,LAG就是取当前行的前一行,LEAD就是取当前行的后一行,因为前后这个概念需要顺序作为前提,所以有个ORDER BY。其实LAG和LEAD还有两个可选参数,比如LAG(val, 3, 0)的意思就是,取向后的第三行,如果没有这样一行,就返回0。默认是LAG(column,1,NULL)。
然后是FIRST_VALUE和LAST_VALUE的例子:
SELECT custid, orderid, val,
FIRST_VALUE(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) AS firstval,
LAST_VALUE(val) OVER(PARTITION BY custid
ORDER BY orderdate, orderid
ROWS BETWEEN CURRENT ROW
AND UNBOUNDED FOLLOWING) AS lastval
FROM Sales.OrderValues
ORDER BY custid, orderdate, orderid;
结果:
讲解一下:以FIRST_VALUE为例,其实就是返回这个分组中某个范围里的第一行,而那个名叫ROWS的window frame unit,我的理解就是继续缩小范围,比如ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW意思就是把范围定在分组的开始到当前行,ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING就是把范围定在当前行到分组的结束。如果不指定这样一个window frame unit,默认的范围的右边界是当前行。而且作者说应当显示指定一个window frame unit。
Aggregate Window Functions:
在SQL Server2012之前,window aggregate functions只支持PARTITION,举个例子:
SELECT orderid, custid, val,
SUM(val) OVER() AS totalvalue,
SUM(val) OVER(PARTITION BY custid) AS custtotalvalue
FROM Sales.OrderValues;
结果:
之前讲过,如果你不指定PARTITION那么范围就是整个结果集。当然,一般都会用window function的值和当前值做一个计算,比如:
SELECT orderid, custid, val,
100. * val / SUM(val) OVER() AS pctall,
100. * val / SUM(val) OVER(PARTITION BY custid) AS pctcust
FROM Sales.OrderValues;
从SQL Server 2012开始,聚合函数支持ordering和framing,例子参考这一章最开始的那个例子。其中的framing部分可以用很多种变化,比如ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING意思就是把范围缩小到当前行向前的两行和向后的一行之间。
考虑以下SQL:
SELECT empid, custid, SUM(qty) AS sumqty
FROM dbo.Orders
GROUP BY empid, custid
UNION ALL
SELECT empid, NULL, SUM(qty) AS sumqty
FROM dbo.Orders
GROUP BY empid
UNION ALL
SELECT NULL, custid, SUM(qty) AS sumqty
FROM dbo.Orders
GROUP BY custid
UNION ALL
SELECT NULL, NULL, SUM(qty) AS sumqty
FROM dbo.Orders;
结果:
我们定义,上面被UNION ALL的四个query分别定义了四个grouping sets:(empid, custid)、(empid)、(custid),以及一个空的 grouping set: ()。但是你这么写很不好,第一是代码很长,第二是性能很差。咋整?用下面这种语法:
SELECT empid, custid, SUM(qty) AS sumqty
FROM dbo.Orders
GROUP BY
GROUPING SETS
(
(empid, custid),
(empid),
(custid),
()
);
这种语法在逻辑上跟上面那个是一样的。但是SQL Server会做优化,提升性能。
还可以用CUBE,同构CUBE你可以得到基于输入参数的所有可能的grouping sets,比如CUBE(a, b, c)就相当于GROUPING SETS( (a, b, c), (a, b), (a, c), (b, c), (a), (b), (c), () )
语法如下:
SELECT empid, custid, SUM(qty) AS sumqty
FROM dbo.Orders
GROUP BY CUBE(empid, custid);
ROLLUP类似,比如ROLLUP(a, b, c)就等于GROUPING SETS( (a, b, c), (a, b), (a), () )
有这么一个函数GROUPING:
SELECT
GROUPING(empid) AS grpemp,
GROUPING(custid) AS grpcust,
empid, custid, SUM(qty) AS sumqty
FROM dbo.Orders
GROUP BY CUBE(empid, custid);
结果:
比如GROUPING(empid)的意思就是:当前这一行,如果empid是作为grouping set中的一员的话,就返回0,否则返回1。
还有个类似的函数GROUPING_ID,它可以接受所有你用在grouping sets里面的元素作为参数,然后返回一个整数(用二进制来看),每一位都代表一个你的元素,0代表是当前grouping set一员,1代表不是。比如你GROUPING_ID(a, b, c, d),如果当前的分组是(a,c)那么就返回0101(二进制)。
《SQL Server 2012 T-SQL基础》读书笔记 - 7.进阶查询的更多相关文章
- SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions
这一章主要是介绍 窗体中的 Aggregate 函数, Rank 函数, Distribution 函数以及 Offset 函数. Window Aggregate 函数 Window Aggrega ...
- SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第1部分)
为了缩小读取操作所涉及范围,本文首先着眼于简单的SELECT查询,然后引入执行更新操作有关的附加过程.最后你会读到,优化性能时SQLServer使用还原工具的相关术语和流程. 关系和存储引擎 如图所示 ...
- SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第2部分)
计划缓存(Plan Cache) 如果SQL Server已经找到一个好的方式去执行一段代码时,应该把它作为随后的请求重用,因为生成执行计划是耗费时间且资源密集的,这样做是有有意义的. 如果没找到被缓 ...
- SQL Sever 各版本下载 SQL Server 2012下载SQL Server 2008下载SQL Server 2005
SQL Server 2012SQL Server 2012 开发版(DVD)(X64,X86)(中文简体)ed2k://|file|cn_sql_server_2012_developer_edit ...
- sql server 2012 导出sql文件
导出表数据和表结构sql文件 在工作中,经常需要导出某个数据库中,某些表数据:或者,需要对某个表的结构,数据进行修改的时候,就需要在数据库中导出表的sql结构,包括该表的建表语句和数据存储语句!在这个 ...
- SQL Server Window Function 窗体函数读书笔记一 - SQL Windowing
SQL Server 窗体函数主要用来处理由 OVER 子句定义的行集, 主要用来分析和处理 Running totals Moving averages Gaps and islands 先看一个简 ...
- SQL Server 2012:SQL Server体系结构——一个查询的生命周期(第3部分)(完结)
一个简单的更新查询 现在应该知道只读取数据的查询生命周期,下一步来认定当你需要更新数据时会发生什么.这个部分通过看一个简单的UPDATE查询,修改刚才例子里读取的数据,来回答. 庆幸的是,直到存取方法 ...
- SQL Server 2012 - 动态SQL查询
动态SQL的两种执行方式:EXEC @sql 和 EXEC sys.sp_executesql @sql DECLARE @c_ids VARCHAR(200) SET @c_ids ='1,2' - ...
- SQL Server 2012 - 数据库的基础操作
数据库基本操作 --新建数据库卡 use master go create database SchoolDB on ( Name=SchoolDB, FileName='D;\DB\SchoolDB ...
随机推荐
- J.U.C|一文搞懂AQS(转)
提到JAVA加锁,我们通常会想到synchronized关键字或者是Java Concurrent Util(后面简称JCU)包下面的Lock,今天就来扒一扒Lock是如何实现的,比如我们可以先提出一 ...
- SharePoint自己定义程序页面部署 不用重新启动IIS
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/dz45693/article/details/30840255 SharePoint的部署方式默认是 ...
- 学习Golang语言(6):类型--切片
学习Golang语言(1): Hello World 学习Golang语言(2): 变量 学习Golang语言(3):类型--布尔型和数值类型 学习Golang语言(4):类型--字符串 学习Gola ...
- springboot2.0-统一处理返回结果和异常情况
一.统一处理返回结果和异常处理的原因: 1.在springboot项目里我们希望接口返回的数据包含至少三个属性: a.code:请求接口的返回码,成功或者异常等返回编码,例如定义请求成功,code = ...
- 【问题解决方案】visudo: /etc/sudoers is busy, try again later
参考链接: 博客园:visudo: /etc/sudoers is busy, try again later CSDN:Shell 获取进程号并杀掉该进程 注:找到几篇相同的参考内容,都是只有查看进 ...
- node静态资源服务器的搭建----访问本地文件夹(搭建可访问静态文件的服务器)
我们的目标是实现一个可访问静态文件的服务器,即可以在浏览器访问文件夹和文件,通过点击来查看文件. 1.先创建一个文件夹anydoor,然后在该文件夹里npm init一个package.json文件, ...
- C# List<Object>值拷贝
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Run ...
- Thinkphp5 手册
thinkphp5 手册 https://www.kancloud.cn/manual/thinkphp5/118003
- 4Linux 终端命令格式
Linux 终端命令格式 转自 目标 了解终端命令格式 知道如何查阅终端命令帮助信息 01. 终端命令格式 command [-options] [parameter] 说明: command:命令名 ...
- 【学习笔记】Minkowski和
这还是个被我咕了N久的玩意 Minkowski和是一个奇怪的玩意 他长这样 $S={a+b \| a \in A , b \in B}$ AB可以是点集也可是向量集(显然) 他可以处理一些奇怪的东西 ...