Sql Service的艺术 SQL聚合函数的应用

Posted 漠北的苍鹰

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sql Service的艺术 SQL聚合函数的应用相关的知识,希望对你有一定的参考价值。

SQL提供的聚合函数有求和,最大值,最小值,平均值,计数函数等。

聚合函数及其功能:

函数名称 函数功能
SUM() 返回选取结果集中所有值的总和
MAX() 返回选取结果集中所有值的最大值
MIN() 返回选取结果集中所有值的最小值
AVG() 返回选取结果集中所有值的平均值
COUNT() 返回选取结果集中行的数目

  学习本节所需要的两张表:

CREATE TABLE TEACHER
(
    ID INT IDENTITY (1,1) PRIMARY KEY ,  --主键,自增长
    TNO INT NOT NULL, --教工号
    TNAME CHAR(10) NOT NULL, --教师姓名
    CNO INT NOT NULL, --课程号
    SAL INT, --工资
    DNAME CHAR(10) NOT NULL, --所在系
    TSEX CHAR(2) NOT NULL, --性别
    AGE INT NOT NULL --年龄
)
INSERT INTO dbo.TEACHER VALUES( 1,王军,4,400,数学,,32)
INSERT INTO dbo.TEACHER VALUES( 2,李彤,5,6600,生物,,54)
INSERT INTO dbo.TEACHER VALUES( 3,王永军,1,1000,计算机,,45)
INSERT INTO dbo.TEACHER VALUES( 4,刘晓婧,2,8000,计算机,,23)
INSERT INTO dbo.TEACHER VALUES( 5,高维,8,6000,电子工程,,54)
INSERT INTO dbo.TEACHER VALUES( 6,李伟,7,230,机械工程,,23)
INSERT INTO dbo.TEACHER VALUES( 7,刘辉,3,0,生物,,65)
INSERT INTO dbo.TEACHER VALUES( 8,刘伟,9,500,计算机,,23)
INSERT INTO dbo.TEACHER VALUES( 9,刘静,12,0,经济管理,,45)
INSERT INTO dbo.TEACHER VALUES( 10,刘奕锴,13,70000,计算机,,65)
INSERT INTO dbo.TEACHER VALUES( 11,高维,14,70000,经济管理,,61)

CREATE TABLE COURSE
(
    ID INT IDENTITY (1,1) PRIMARY KEY ,  --主键,自增长
    CNO INT NOT NULL, --课程号
    CNAME CHAR(30) NOT NULL, --课程名称
    CTIME INT NOT NULL, --学时
    SCOUNT INT NOT NULL, --容纳人数
    CTEST SMALLDATETIME NOT NULL, --考试时间
)
INSERT INTO dbo.COURSE VALUES( 4,应用数学基础,48,120,2006-7-10)
INSERT INTO dbo.COURSE VALUES( 5,生物工程概论,32,80,2006-7-8)
INSERT INTO dbo.COURSE VALUES( 1,计算机软件基础,32,70,2006-7-8)
INSERT INTO dbo.COURSE VALUES( 2,计算机硬件基础,24,80,2006-6-28)
INSERT INTO dbo.COURSE VALUES( 8,模拟电路设计,28,90,2006-7-10)
INSERT INTO dbo.COURSE VALUES( 7,机械设计实践,48,68,2006-7-14)
INSERT INTO dbo.COURSE VALUES( 3,生物化学,32,40,2006-7-2)
INSERT INTO dbo.COURSE VALUES( 9,数据库设计,16,80,2006-7-1)
INSERT INTO dbo.COURSE VALUES( 6,设计理论,28,45,2006-6-30)
INSERT INTO dbo.COURSE VALUES( 10,计算机入门,25,150,2006-6-29)
INSERT INTO dbo.COURSE VALUES( 11,数字电路设计基础,30,125,2006-6-20)
INSERT INTO dbo.COURSE VALUES( 12,数字电路设计基础%,30,125,2006-6-20)
INSERT INTO dbo.COURSE VALUES( 13,_设计理论,28,45,2006-6-30)

  

  一、求和函数——SUM()

--求所有老师的工资总和
    SELECT SUM(SAL) AS TOTAL_SAL FROM dbo.TEACHER

  注意:

    SUM()函数只能作用于数值类型数据。

     对某列求和,如果存在NULL值,则SUM函数会忽略该值。

 

  二、计数函数——COUNT()

   --使用COUNT(),对表的总行数
    SELECT COUNT(*) AS TOTAL FROM dbo.TEACHER

    --使用COUNT(),对表列的数据计数
    --SAL列有一行数据为空,所以结果与其他两列不同
    SELECT COUNT(TNAME) AS TOTAL,COUNT(SAL) AS TOTAL,COUNT(DNAME) AS TOTAL FROM dbo.TEACHER

    --使用COUNT(),对表的列的数据一起包含查询,需要用到CAST,以及"+"连接符
    --ZongLie 是包含SAL和TNAME两列的数据,放在一起查询的
    SELECT COUNT(TNAME) AS Total_Name,COUNT(SAL) AS Total_Sal,COUNT(DNAME) AS Total_Name,COUNT(CAST(SAL AS VARCHAR(10))+TNAME) AS ZongLie FROM dbo.TEACHER

    --使用COUNT(),满足where条件的查询
    SELECT COUNT(*) AS TOTAL FROM dbo.TEACHER WHERE TSEX=

  注意一下两点:

    COUNT(*),计算表中行的总数,即使表中行的数据为null,也被计入在内。
    COUNT(column),计算column列包含行的数目,如果该列中某行数据为null,则该行不计入总数。

 

  三、最大/最小值函数——MAX()/MIN()

    --MAX()的使用,查询工资最高/最低
    SELECT MAX(SAL) AS 最高工资,MIN(SAL) AS 最低工资 FROM dbo.TEACHER

    --以下是两种错误的写法,聚合函数的处理是数据组,他将teacher看作是一个组,而TNAME,SAL的数据没有进行分组,所以select语句没有逻辑意义。
    --该列没有包含在聚合函数或 GROUP BY 子句中。
    SELECT TNAME,MAX(SAL) FROM dbo.TEACHER
    --聚合不应出现在 WHERE 子句中,除非该聚合位于 HAVING 子句或选择列表所包含的子查询中,并且要对其进行聚合的列是外部引用。
    SELECT * FROM dbo.TEACHER WHERE AGE=MAX(AGE)

    --那么接下来演示正确子句使用MAX/MIN查询
    --子句中要写完整的select查询语句
    SELECT TNO,TNAME,SAL,DNAME,AGE FROM dbo.TEACHER WHERE AGE=(SELECT MAX(AGE) FROM dbo.TEACHER)  --显示年龄最大老师的信息

    --MAX()/MIN()不仅可以用作于数值类型数据,也可以用作于字符串或者日期类型
    --字符串类型是根据字母A~Z排序的:
    SELECT MAX(TNAME) FROM dbo.TEACHER   --结果:王永军   开头字母:W

    --MAX()/MIN()用于时间类型
    SELECT MAX(CTEST) AS 近,MIN(CTEST) AS 远 FROM dbo.COURSE

  注意:

    确认列中的最大值/最小值时,MAX,MIN函数会忽略NULL值。但是,如果该列所有行的值都是NULL,则函数返回NULL。

 

  四、均值函数--AVG()

    --均值函数是用来计算列的数据平均值的,跟SUM()一样,只能用来计算数值类型
    SELECT AVG(SAL) FROM dbo.TEACHER     --计算工资的平均值

    --利用COUNT() SUM() AVG()来看下求平均值的过程
    SELECT AVG(SAL) AS AVG函数算的平均工资,COUNT(*) AS 总人数,SUM(SAL)/COUNT(TNAME) AS 总的工资除总的人数 FROM dbo.TEACHER
    --运行结果发现,AVG算的平均工资跟手动算的不一样,因为AVG算平均工资的时候忽略了“NULL”,所排除了一个人数,
    --而我们平常不管有没有工资,都要把这个人算上在求平均,所以导致结果不一样,网上也有有不同说法,可自行斟酌,仅代表个人想法
    
    SELECT SUM(SAL) AS 工资总和 FROM dbo.TEACHER   --162730   162730/12=13560  
    SELECT COUNT(SAL) AS 工资列的总行数排除NULL FROM dbo.TEACHER   --11     162730/11=14793 工资有一个为空,忽略
    SELECT COUNT(TNAME) AS 人数列的总行数排除NULL FROM dbo.TEACHER  --12
    SELECT COUNT(*) AS 表的总行数 FROM dbo.TEACHER  --12
    SELECT * FROM dbo.TEACHER  --表数据

    --带where子句使用条件限制平均值
    SELECT AVG(SAL) FROM dbo.TEACHER WHERE DNAME=电子工程   --这个结果同上
    SELECT * FROM dbo.TEACHER WHERE DNAME=电子工程 

    --聚合分析的重值处理
    SELECT COUNT(ALL SAL) AS 所有的 FROM dbo.TEACHER
    SELECT COUNT(DISTINCT SAL) AS 除去重复的 FROM dbo.TEACHER
    SELECT * FROM dbo.TEACHER  --表数据
    --使用ALL后,计算出所有行数,使用distinct后,排除了重复的数值
    --除了"COUNT(*)"函数外,其他函数在计算的过程中都忽略了NULL,排除NULL进行分析计算

    --聚合函数也可以组合使用,即在一条select语句中,可以使用多个聚合函数
    SELECT COUNT(*) AS 行数,MIN(AGE) AS 最小年龄,MAX(SAL) AS 最高工资,AVG(AGE) AS 平均年龄,SUM(SAL)/COUNT(*) AS 平均工资 FROM dbo.TEACHER

 

  五、组合查询GROUP BY,HAVING

--GROUP BY子句分组查询
    SELECT TSEX+教师 AS 老师,AVG(SAL) AS 平均工资 FROM dbo.TEACHER GROUP BY TSEX  --男 女老师的平均工资
    --来分析一下DBMS执行实例的步骤
    --首先执行FROM子句,将表TEACHER作为中间表
    --如果有WHERE子句,DBMS则根据其中的搜索条件,从中间表中去除那些值为False的列.这里没有WHERE子句,所以DBMS跳过了这个步骤
    --根据GROUP BY子句制定的分组列即TSEX,DBMS将中间表中的数据进行分组。这里TSEX的值为‘男’,另一组中TSEX值为‘女’
    --DBNS为每个行组计算SELECT子句中的值,并为每组生成查询结果中的一行。对于TSEX值为‘男’的行组,SELECT子句首先执行‘TSEX+教师’,得到‘男教师’列值,再执行‘AVG(SAL)’,求得该行组中的SAL的均值,将这两个值作为结果表中的一条记录;同样,对TESX值为‘女’的行组,进行类似的操作得到另一条记录

    --GROUP BY子句根据多列组合行
    SELECT DNAME,TSEX,COUNT(*) AS 人数 FROM dbo.TEACHER GROUP BY DNAME,TSEX   --查询各系男女老师的人数
    --会发现有的没有男或女,因为没有值,系统默认为NULL,不显示了

    --GROUP BY子句中的NULL处理
    SELECT SAL AS 工资,COUNT(*) AS 数量 FROM dbo.TEACHER GROUP BY SAL

    --HAVING子句
    --GROUP BY子句会根据所选的列进行分组,但实际上,我们往往还需要删除那些不满足条件的行组,为了实现这个功能SQL提供了HAVING子句。
    --通常GROUP BY与HAVING使用
    SELECT DNAME AS 系,COUNT(*) AS 数量 FROM dbo.TEACHER GROUP BY DNAME HAVING COUNT(*)>=2   --选择系的数量大于等2
    --如果指定了GROUP BY子句,那么HAVING子句定义的搜索条件将作用于这个GROUP BY子句创建的那些组
    --如果指定的WHERE子句而没有指定GROUP BY子句,那么HAVING子句定义的搜索条件将作用于WHERE子句的输出,并把这个输出看作是一个组
    --如果既没有指定GROUP BY子句也没有指定WHERE子句,那么HAVING子句定义的搜索条件将作用于FROM子句的输出并把这个输出看作一个组
    SELECT * FROM dbo.TEACHER

    --HAVING与where子句不同的作用
    SELECT DNAME AS 系,COUNT(TSEX) AS 数量 FROM dbo.TEACHER WHERE TSEX= GROUP BY DNAME   --女老师的系拥有女老师的数量
    --不能把单个的TSEX的值应用于组,包括HAVING子句中的列必须是组列。因此,在这种情况下,WHERE子句就不可能用HAVING子句代替
    --在数据的分组聚合分析中,HAVING子句与WHERE子句也可以共存。WHERE子句在分组之前过滤,而HAVING子句则过滤分组后的数据

    SELECT DNAME AS 系,COUNT(TSEX) AS 数量 FROM dbo.TEACHER WHERE TSEX= GROUP BY DNAME HAVING COUNT(TSEX)>=2  --女老师的系拥有至少2个女老师的数量
    --通常情况下,HANVING子句都与GROUP BY子句一起使用,这样就可以聚合相关数据,然后筛选这些数据,以进一步细化搜索。但如果没有GROUP BY子句,HAVING子句也可以单独使用。


    --HAVING子句的单独使用
    SELECT COUNT(TSEX) FROM dbo.TEACHER WHERE TSEX= HAVING COUNT(TSEX)>3  --数量大于3的女老师

  注意:

    GROUP BY子句依据column列里的数据对行进行分组,即具有相同值得行被划为一组。它一般与聚合函数同时使用。当然,这里的SUM函数也可以是其他聚合函数。
    所有的组合列(GROUP BY子句中列出的列)必须来自于FROM子句列出的表,不能根据实际值、聚合函数结果或者其他表达式计算的值来对行分组。

 

  来总结一下SELECT语句查询子句:

  SELECT语句查询子句及其所有子句

顺序号 子句关键词 子句功能
1 SELECT 从指定表中取出指定列的数据
2 FROM 制定要查询操作的表
3 WHERE 用来规定一种选择查询的标准
4 GROUP BY 对结果集进行分组,常与聚合函数一起使用
5 HAVING 返回选取的结果集中行的数目
6 ORDER BY 指定分组的搜寻条件

  如果在同一个SELECT语句中用到上表的一下查询子句,则各查询顺序排列由低到高的顺序。因此,完整的SELECT查询语句可以如下:

    --SELECT select_list
    --FROM table_source
    --[WHERE search_condition]
    --[GROUP BY group_by_expression]
    --[HAVING search_condition]
    --[ORDER BY order_expression [ASC \ DESC]]
    --[]是可选项

--至少有两名女教师的系拥有的女教师数量,并且按数量排序 SELECT DNAME AS 系名,COUNT(TSEX) AS 数量 FROM dbo.TEACHER WHERE TSEX
= GROUP BY DNAME HAVING COUNT(TSEX)>=2 ORDER BY 数量

 




以上是关于Sql Service的艺术 SQL聚合函数的应用的主要内容,如果未能解决你的问题,请参考以下文章

Sql Service的艺术 SQL多表查询

sql聚合函数的应用

sql聚合函数的应用

所有的sql聚合函数的应用例题 谢谢

在 Apache Druid 中使用 SQL 将聚合函数应用于某些列

什么时候可以将聚合函数嵌套在标准 SQL 中?