开窗函数具有浅深深度解(1)

在打开窗口函数之前,SQL语句存在许多难以解决的问题。其中很多是通过复杂的相关子查询或存储过程完成的,为了解决这些问题,2003,ISO标准增加了窗口函数,而窗口函数的使用使得这些经典问题很容易解决。

对于窗口功能,支持如MSSQLServer、Oracle、DB2等主流数据库提供,但不幸的是,MySQL尚未为窗口函数提供支持。

为了更清楚地了解,我们将建立的表进行关联查询(截图在MSSQLServer的结果)。



MySQL,DB2数据库:




创建表t_person

FName VARCHAR(20),
fcity varchar(20),
发哥int,
fsalary int



神谕:



复制代码代码如下所示:

创建表t_person(fname VARCHAR2(20),fcity VARCHAR2(20),发哥int、FSalary INT)





注:以下结果仅在MSSQLServer证明:



的t_person表保存员工信息,该名领域的人的名字,和fcity字段名称的城市,人的所在地。

发哥的领域是员工的年龄,和fsalary领域工作人员的工资。

然后执行以下SQL语句插入一些演示数据到t_person表:




插入t_person(名、fcity,发哥,FSalary)
价值观(',北京,203000);
插入t_person(名、fcity,发哥,FSalary)
值('tim ','chengdu ',214000);
插入t_person(名、fcity,发哥,FSalary)
值(吉姆,北京,223500);
插入t_person(名、fcity,发哥,FSalary)
值('lily ','london ',212000);
插入t_person(名、fcity,发哥,FSalary)
值(约翰,'newyork ',221000);
插入t_person(名、fcity,发哥,FSalary)
值('yaoming,北京,203000);
插入t_person(名、fcity,发哥,FSalary)
值('swing ','london ',222000);
插入t_person(名、fcity,发哥,FSalary)
值('guo ','newyork ',202800);
插入t_person(名、fcity,发哥,FSalary)
值('yuqian,北京,248000);
插入t_person(名、fcity,发哥,FSalary)
值('ketty ','london ',258500);
插入t_person(名、fcity,发哥,FSalary)
值('kitty ','chengdu ',253000);
插入t_person(名、fcity,发哥,FSalary)
值('merry,北京,233500);
插入t_person(名、fcity,发哥,FSalary)
值('smith ','chengdu ',303000);
插入t_person(名、fcity,发哥,FSalary)
值(比尔,北京,252000);
插入t_person(名、fcity,发哥,FSalary)
值('jerry ','newyork ',243300);


看看桌子上的东西:



复制代码代码如下所示:

SELECT * FROM t_person




窗函数简介

与聚合函数一样,它是窗口行集组聚合计算的函数,但它不同于普通的聚合函数,每个函数都返回一个值,每个组的窗口函数可以返回多个值,因为窗口函数执行聚合计算,行集组是窗口。

在ISO SQL中,这样的函数被定义为一个窗口函数,它被称为Oracle中的解析函数,在DB2中它被称为OLAP函数。

为了计算总人数,我们可以执行以下SQL语句:

复制代码代码如下所示:

select count(*)从t_person



除了这个简单的方法使用,有时需要访问这些集合在排不在聚合函数计算的值。例如,我们想查询员工信息(城市、年龄)月薪低于5000元,并显示其工资是每行少超过5000元的员工数量。尝试编写以下SQL语句:


选择fcity,发哥,计数(*)

从t_person

这里fsalary<5000


在执行上面的SQL之后,我们将得到以下错误信息:

的column't_person。fcity'in选择列表无效,因为列不包含在聚合函数或GROUP BY子句。

这是因为在聚合函数中未包含的所有列必须在组子句中声明,

可以进行以下修改:


选择fcity,发哥,计数(*)

从t_person

在fsalary<5000

集团通过fcity,发哥


执行之后,我们可以在输出结果中看到以下执行结果:




执行结果与我们想象的完全不同,因为按组子句被分组结果集,因此由聚合函数计算的对象不再是所有结果集,而是每个组。



这个问题是可以解决的子查询的SQL如下:


选择fcity,发哥,

select count(*)从t_person
在fsalary<5000

从t_person
在fsalary<5000


执行之后,我们可以在输出结果中看到以下执行结果:


虽然子查询可以解决这个问题,子查询的使用是很麻烦的。使用窗口函数可以大大简化实现。下面的SQL语句表明,如果使用窗口函数来实现同样的效果,




选择fcity,发哥,计数(*)在()
从t_person
在fsalary<5000




执行之后,我们可以在输出结果中看到以下执行结果:


正如您所看到的,与聚合函数不同,窗口函数在聚合函数中添加一个关键字。

窗口函数的调用格式是:

函数名(列)超过(选项)

过度关键字表示函数被视为一个窗口函数,而不是一个聚合函数。

在上面的例子中,窗口函数计数(*)超过()返回每个查询结果行的所有行的行数。

如果超过关键字的括号中的选项是空的,则开窗函数将聚合结果集中的所有行。

以上描述是窗口功能的基本用法,希望对您有所帮助!