mgm6608美高梅app下载-mgm集团美高梅登录

mgm6608美高梅app下载以独家报道、社区、博客和专题策划等方式引领产业潮流,mgm集团美高梅登录为足球爱好者以及体育爱好者提供足球上网,让你无后顾之忧!,拥有多位香港乐坛红星。

  在开窗函数出现之前存在着很多用 SQL,分析

日期:2019-09-29编辑作者:mgm集团美高梅登录

三. 分析函数 (Analytic Function)

  在开窗函数出现之前存在着很多用 SQL 语句很难解决的问题,很多都要通过复杂的相关子查询或者存储过程来完成。SQL Server 2005 引入了开窗函数,使得这些经典的难题可以被轻松的解决。

SELECT EMPNO,
       ENAME,
       DEPTNO,
       SAL,
       --注意ROWS BETWEEN unbounded preceding AND current row  是指第一行至当前行的汇总
       SUM(SAL) OVER(PARTITION BY DEPTNO 
                     ORDER BY ENAME 
                     ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_sal
  FROM SCOTT.EMP;

参考:

 

    

drop table if exists test_aggregate;

create table test_aggregate
(
event_id      varchar(100),
rk            int,
price         int
)

insert into test_aggregate
values
('a',1,10),
('a',2,10),
('a',3,50),
('b',1,10),
('b',2,20),
('b',3,30)


--1. 没有窗口函数时,用子查询
select a.event_id, 
       a.rk,  --build ranking column if needed
       a.price, 
     (select sum(price) from test_aggregate b where b.event_id = a.event_id and b.rk <= a.rk) as totalprice 
  from test_aggregate a


--2. 从SQL Server 2012起,用窗口函数
--2.1 
--没有PARTITION BY, 没有ORDER BY,为全部总计;
--只有PARTITION BY, 没有ORDER BY,为分组小计;
--只有ORDER BY,没有PARTITION BY,为全部累计求和(RANGE选项,见2.2)
select *,
     sum(price) over() as TotalPrice,
     sum(price) over(partition by event_id) as SubTotalPrice,
       sum(price) over(order by rk) as RunningTotalPrice
  from test_aggregate a

--2.2 注意ORDER BY列的选择,可能会带来不同结果
select *,
     sum(price) over(partition by event_id order by rk) as totalprice 
  from test_aggregate a
/*
event_id    rk    price    totalprice
a    1    10    10
a    2    10    20
a    3    50    70
b    1    10    10
b    2    20    30
b    3    30    60
*/

select *,
     sum(price) over(partition by event_id order by price) as totalprice 
  from test_aggregate a
/*
event_id    rk    price    totalprice
a    1    10    20
a    2    10    20
a    3    50    70
b    1    10    10
b    2    20    30
b    3    30    60
*/

--因为ORDER BY还有个子选项ROWS/RANGE,不指定的情况下默认为RANGE UNBOUNDED PRECEDING AND CURRENT ROW 
--RANGE按照ORDER BY中的列值,将相同的值的行均视为当前同一行
select  *,sum(price) over(partition by event_id order by price) as totalprice from test_aggregate a
select  *,sum(price) over(partition by event_id order by price range between unbounded preceding and current row) as totalprice from test_aggregate a

--如果ORDER BY中的列值有重复值,手动改用ROWS选项即可实现逐行累计求和
select  *,sum(price) over(partition by event_id order by price rows between unbounded preceding and current row) as totalprice from test_aggregate a

Ranking Window Functions

< OVER_CLAUSE > :: =

   OVER ( [ PARTITION BY value_expression , ... [ n ] ]

          <ORDER BY_Clause> )

运行结果:

假设有个门禁系统,在员工每次进门时写入一条记录,记录了“身份号码”,“进门时间”,“衣服颜色",查询每个员工最后一次进门时的“衣服颜色”。

 

窗口函数(累计和、移动平均值等)

窗口函数可用来计算累计和、移动平均值和中心平均值等,具体如下:

SELECT - OVER Clause (Transact-SQL)

  窗口是用户指定的一组行。开窗函数计算从窗口派生的结果集中各行的值。开窗函数分别应用于每个分区,并为每个分区重新启动计算。

计算移动平均值

计算本月与前3个月之间销量的移动平均值,SQL语句如下:

SELECT month,

SUM(amount) AS month_amount,

AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS moving_average

FROM all_sales

where year = 2003

GROUP BY month

ORDER BY month;

对移动平均值部分AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)解析如下:

  • AVG(SUM(amount))内部的sum(amount)计算月销量和,外部的avg()计算平均值。
  • ORDER BY month 按月份对查询读取的记录进行排序(这是必须的,因为只有排序后才能做累积或前后求平均值)。
  • ROWS BETWEEN 3 PRECEDING AND CURRENT ROW定义了窗口的起点为当前记录的前3条记录,窗口的终点为当前记录。

帮助文档里的代码示例很全。

  例如:

--显示各部门员工的工资,并附带显示该部分的最高工资。
SELECT E.DEPTNO,
       E.EMPNO,
       E.ENAME,
       E.SAL,
       LAST_VALUE(E.SAL) 
       OVER(PARTITION BY E.DEPTNO 
            ORDER BY E.SAL ROWS 
            --unbounded preceding and unbouned following针对当前所有记录的前一条、后一条记录,也就是表中的所有记录
            --unbounded:不受控制的,无限的
            --preceding:在...之前
            --following:在...之后
            BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) MAX_SAL
  FROM EMP E;

SELECT SalesOrderID, ProductID, OrderQty

   ,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS 'Total'

   ,CAST(1.0 * OrderQty / SUM(OrderQty) OVER(PARTITION BY SalesOrderID)

       *100 AS DECIMAL(5,2))AS 'Percent by ProductID'

FROM SalesOrderDetail

WHERE SalesOrderID IN(43659,43664);

 

二. 聚合函数 (Aggregate Function)

 

 运行结果:

代码示例1:总计/小计/累计求和

 

 

排序函数中,ROW_NUMBER()较为常用,可用于去重、分页、分组中选择数据,生成数字辅助表等等;

从 转

运行结果:

--移动平均,举个例子,就是求前N天的平均值,和股票市场的均线类似
drop table if exists test_moving_avg

create table test_moving_avg
(
ID    int, 
Value int,
DT    datetime
)

insert into test_moving_avg 
values
(1,10,GETDATE()-10),
(2,110,GETDATE()-9),
(3,100,GETDATE()-8),
(4,80,GETDATE()-7),
(5,60,GETDATE()-6),
(6,40,GETDATE()-5),
(7,30,GETDATE()-4),
(8,50,GETDATE()-3),
(9,20,GETDATE()-2),
(10,10,GETDATE()-1)

--1. 没有窗口函数时,用子查询
select *,
(select AVG(Value) from test_moving_avg a where a.DT >= DATEADD(DAY, -5, b.DT) AND a.DT < b.DT) AS avg_value_5days
from test_moving_avg b

--2. 从SQL Server 2012起,用窗口函数
--三个内置常量,第一行,最后一行,当前行:UNBOUNDED PRECEDING, UNBOUNDED FOLLOWING, CURRENT ROW 
--在行间移动,用BETWEEN m preceding AND n following (m, n > 0)
SELECT *,
       sum(value) over (ORDER BY DT ROWS BETWEEN 5 preceding AND CURRENT ROW) moving_sum,
       avg(value) over (ORDER BY DT ROWS BETWEEN 4 preceding AND CURRENT ROW) moving_avg1,
       avg(value) over (ORDER BY DT ROWS BETWEEN 5 preceding AND 1 preceding) moving_avg2,
       avg(value) over (ORDER BY DT ROWS BETWEEN 3 preceding AND 1 following) moving_avg3
FROM  test_moving_avg
ORDER BY DT

  可参考 

示例目的:按照deptno分组,然后计算每组值的总和

drop table if exists test_ranking

create table test_ranking
( 
id int not null,
name varchar(20) not null,
value int not null
) 

insert test_ranking 
select 1,'name1',1 union all 
select 1,'name2',2 union all 
select 2,'name3',2 union all 
select 3,'name4',2

select id , name, ROW_NUMBER() over (PARTITION by id ORDER BY name) as num
from test_ranking

select id , name, ROW_NUMBER() over (PARTITION by id) as num
from test_ranking
/*
Msg 4112, Level 15, State 1, Line 1
The function 'ROW_NUMBER' must have an OVER clause with ORDER BY.
*/

--ORDERY BY后面给一个和原表无关的派生列
select id , name, ROW_NUMBER() over (PARTITION by id ORDER BY GETDATE()) as num
from test_ranking

select id , name, ROW_NUMBER() over (PARTITION by id ORDER BY (select 0)) as num
from test_ranking

2. 示例

示例目的:显示各部门员工的工资,并附带显示该部分的最高工资。

一. 排序函数(Ranking Function)

 

示例目标:当前行至最后一行的汇总

  1. 排序函数 (Ranking Function) ;

  2. 聚合函数 (Aggregate Function) ;

  3. 分析函数 (Analytic Function) ;

  4. NEXT VALUE FOR Function, 这是给sequence专用的一个函数;

1. 语法

 运行结果:

从SQL Server 2005起,SQL Server开始支持窗口函数 (Window Function),以及到SQL Server 2012,窗口函数功能增强,目前为止支持以下几种窗口函数:

mgm6608美高梅app下载, 

计算中心平均值

计算当前月份前、后各一个月的销量移动平均值,SQL语句如下:

SELECT month,

SUM(amount) AS month_amount,

AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS moving_average

FROM all_sales

where year = 2003

GROUP BY month

ORDER BY month;

对中心平均值部分AVG(SUM(amount)) OVER (ORDER BY month ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)解析如下:

  • AVG(SUM(amount))内部的sum(amount)计算月销量和,外部的avg()计算平均值。
  • ORDER BY month 按月份对查询读取的记录进行排序(这是必须的,因为只有排序后才能做累积或前后求平均值)。
  • ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING定义了窗口的起点是当前记录之前的那条记录,窗口的终点是当前记录之后的那条记录。

代码示例2:分组中某列最大/最小值,对应的其他列值

2. 示例

 

 

 

RANK()和DENSE_RANK()

rank()和dense_rank()函数都可用于计算数据项在分组中(在不使用partition by时以所有数据为一个分组)的排名。它们的区别在于rank()在排名相等时,如:有3个第1名时,则下一个排名为第4名,没有2、3名;而dense_rank()则在有3个第1名时,下一个排名为第2名。即,rank()会出现排名间隔,而dense_rank()则不会出现排名间隔。

这两个函数多用于select子句中,在不进行分组的情况下,可以不使用partition by子句。其使用举例如,找出公司所有人工资排名:

select ename,

rank() over (order by sal desc) rank,

dense_rank() over (order by sal desc) dense_rank

from emp;

从语句中可以看出,rank()函数需要有关键字over和order by。而且rank()是一个单值函数,而不是聚合函数。若需要找出每种工作的最高工资在所有工作最高工资中的排名:

select job,

rank() over (order by max(sal) desc) rank,

dense_rank() over (order by max(sal) desc) dense_rank

from emp

group by job;

在排名中,会出现NULL值在前在后的问题,可以在ORDER BY子句之后使用关键字NULLS FIRST/LAST来控制。

本文由mgm6608美高梅app下载发布于mgm集团美高梅登录,转载请注明出处:  在开窗函数出现之前存在着很多用 SQL,分析

关键词:

才能使用Transact-SQL修改DEFAULT约束,以下几种情况

使用SSMS数据库管理工具修改DEFAULT约束 1、连接数据库、选择数据表-》右键点击-》选择设计。 2、在表设计器窗口-》...

详细>>

每个表中要有一个主键,数据库只需要满足第三

1.数据库设计三大范式 #实体的完整性 概述:  实体:即表中的一行(一条记录)代表一个实体(entity)实体完整性的作...

详细>>

解决方法,链接服务器""的 OLE DB 访问接口

在SQL SERVER 2008 R2下用Windows身份认证的登录名创建了一个访问ORACLE数据库的链接服务器xxxxx,测试成功,木有问题,但...

详细>>

qty加上前一笔的eqty,API与文件操作

有一个网友问及,在SQL中,计算每一笔的结余数。他提供的截图说明: 前段时间,一直有练习ASP.NET MVC与WebAPI交互,...

详细>>