SQL 查询之集合运算 & 聚合函数

 

1、集合运算

在数学中,不仅可以对指定的数字个体做四则运算,还可以对指定的集合整体做交并补运算。类似的,在数据库中也是不仅可以对具体的数据行进行增删改查,还可以对查询结果集进行集合运算。SQL Server 中的集合运算有并集运算、差集运算和交集运算三种,本节将逐一讲述。

1.1、并集运算 UNION

并集运算符 UNION 的作用是将两个或多个查询的结果集合并为单个结果集。在 UNION 运算中,需要确保各个子结果集的字段数相同、字段的顺序相同、字段的数据类型兼容。合并结果集的列名始终会取第一个子结果集中的列名,因此,如果要对合并结果集排序,则需要用第一个子结果集的字段名。

参数 ALL 表示将全部行并入结果集中,换句话说合并结果集可能会包含重复行;相反,如果未指定该参数,则会删除重复行。需要注意的是,在做重复判断时,UNION 会把两个 NULL 值被视为相等的。因为 UNION ALL 不需要删除重复行,所以性能比 UNION 要好。因此,除非必须要删除重复行,否则建议一律使用 UNION ALL。

1.1.1、简单 UNION ALL。查询 1 班的男生和 2 班的女生。示例如下:

SELECT * FROM T_Students t1 WHERE t1.ClassId = 1 AND t1.Gender = 1
UNION ALL
SELECT * FROM T_Students t2 WHERE t2.ClassId = 2 AND t2.Gender = 0;

1.1.2、简单 UNION ALL。查询 1 班的男生和该班的男生人数。示例如下:

SELECT 1 cnt,t1.Code,t1.Name FROM T_Students t1 WHERE t1.ClassId = 1 AND t1.Gender = 1
UNION ALL
SELECT COUNT(1),NULL,NULL FROM T_Students t2 WHERE t2.ClassId = 1 AND t2.Gender = 1;

查询结果如下:

cnt         Code                           Name
----------- ------------------------------ ------------------------------
1 S330102001 郑强
1 S330102002 肖俊生
1 S330300007 钱波
1 S330104009 金桥
4 NULL NULL

1.1.3、UNION 与 ORDER BY。查询 1 班的男生和 2 班的女生,并且将最终结果集按年龄从大到小排序。示例如下:

SELECT * FROM T_Students t1 WHERE t1.ClassId = 1 AND t1.Gender = 1
UNION ALL
SELECT * FROM T_Students t2 WHERE t2.ClassId = 2 AND t2.Gender = 0
ORDER BY t1.Birthday;

1.1.4、UNION 与 SELECT INTO。创建一个活动学生表,并将 1 班的男生和 2 班的女生加入其中。示例如下:

SELECT t1.Code,t1.Name,t1.Gender,t1.Birthday
INTO T_ActivityStudents
FROM T_Students t1
WHERE t1.ClassId = 1 AND t1.Gender=1
UNION ALL
SELECT t2.Code,t2.Name,t2.Gender,t2.Birthday
FROM T_Students t2
WHERE t2.ClassId = 2 AND t2.Gender=0;

1.1.5、通过括号来改变 UNION 的运算顺序。示例如下:

WITH t AS(
SELECT TOP(3) * FROM T_Students t WHERE t.ClassId = 1 ORDER BY t.Birthday
)
SELECT * FROM t
UNION ALL(
SELECT * FROM t
UNION
SELECT * FROM t
);

简单说明一下:首先,上例会返回 6 条数据。其次,很明显 CTE 中包含了年龄最大的 3 个学生。然后,括号会提升运算符的优先级,而且 UNION 会删除重复行,所以括号中会返回 3 条数据。最后,UNION ALL 不会删除重复行,所以最终返回的 6 条数据是第一个查询返回的 3 条数据加上括号中两个查询共同产生的 3 条数据。

1.2、差集运算 EXCEPT

差集运算符 EXCEPT 的作用是比较两个查询的结果集,然后返回左侧结果集包含但右侧结果集不包含的行,且不包含重复行。与 UNION 运算相同,EXCEPT 运算也要求各个子结果集的字段数相同、顺序相同、类型兼容。且 EXCEPT 也会把两个 NULL 值被视为相等的。示例如下:

SELECT * FROM T_GoodStudents t1 WHERE t1.Gender = 0
EXCEPT
SELECT * FROM T_GoodStudents t2 WHERE t2.Birthday < '2000-01-01';

注意:上例是用女生这个结果集减去非 00 后学生结果集,但得到的结果集并不一定是 00 后女生,因为女生的出生日期可能是 NULL,所以最终的结果集是 00 后女生加上出生日期为 NULL 的女生。

类似于 UNION:EXCEPT 也可以与 ORDER BY 连用来给差集(最终的结果集)排序,而且差集的列名也跟第一个子结果集的列名相同。EXCEPT 还可以与 SELECT INTO 连用将差集拷贝到一个新表中。当有多个 EXCEPT 时也可以通过括号来改变运算顺序。具体用法可参考 UNION 的示例。

1.3、交集运算 INTERSECT

交集运算符 INTERSECT 的作用是比较两个查询的结果集,然后返回左侧结果集和右侧结果集都包含的行,且不包含重复行。与 UNION 运算相同,INTERSECT 运算也要求各个子结果集的字段数相同、顺序相同、类型兼容。且 INTERSECT 也会把两个 NULL 值被视为相等的。示例如下:

SELECT * FROM T_GoodStudents t1 WHERE t1.Gender = 0
INTERSECT
SELECT * FROM T_GoodStudents t2 WHERE t2.Birthday < '2000-01-01';

注意:上例是取女生这个结果集和非 00 后学生结果集的交集,但得到的结果集并不一定是非 00 后女生,因为女生的出生日期可能是 NULL,所以最终的结果集是非 00 后女生加上出生日期为 NULL 的女生。

类似于 UNION:INTERSECT 也可以与 ORDER BY 连用来给交集(最终的结果集)排序,而且交集的列名也跟第一个子结果集的列名相同。INTERSECT 还可以与 SELECT INTO 连用将交集拷贝到一个新表中。当有多个 INTERSECT 时也可以通过括号来改变运算顺序。具体用法可参考 UNION 的示例。

1.4、集合运算小结

上文逐一讲述了各个集合运算符的语法和用途。其实这些集合运算符不仅可以单独使用,还可以结合起来使用,示例如下:

SELECT t1.Id,t1.Name,t1.Gender,t1.Birthday FROM T_Students t1 WHERE t1.ClassId = 1
UNION ALL
SELECT t2.Id,t2.Name,t2.Gender,t2.Birthday FROM T_Students t2 WHERE t2.ClassId = 3
EXCEPT
SELECT * FROM T_GoodStudents t3 WHERE t3.Birthday < '2000-01-01'
INTERSECT
SELECT * FROM T_GoodStudents t4 WHERE t4.Gender = 1;

注意:上例的运算顺序并不是先 UNION ALL,然后 EXCEPT,再 INTERSECT。因为 INTERSECT 比 EXCEPT 和 UNION 的优先级要高,而 EXCEPT 与 UNION 的优先级相同,所以上例的实际运算顺序是先 INTERSECT,然后 UNION ALL,最后再用 UNION ALL 的结果集减 INTERSECT 的结果集,即最后进行 EXCEPT 运算。

2、聚合函数

聚合函数的作用是对一组值执行计算,并返回单个结果值。聚合函数只能在 SELECT 子句或 HAVING 子句中作为表达式来用。求行数函数 COUNT、求和函数 SUM、求最大值函数 MAX、求最小值函数 MIN、求平均值函数 AVG,这 5 个函数是最常用的聚合函数,主流的关系型数据库也都支持它们。

其实常见的关系型数据库都支持很多聚合函数,但其中大部分都是非标准的,各个数据库之间的差别也比较大,而且这些函数也都不常用。个人建议实际工作中不要用这些函数,以免跟某个具体的数据库绑死。

2.1、求行数函数 COUNT

求行数函数 COUNT 会返回查询结果集的行数。COUNT 函数中可以是一个具体的列,也可以是代表所有列的星号,还可以是一个具体的常量或变量。示例如下:

SELECT COUNT(t.Id) result FROM T_Students t; -- result:32 rows
SELECT COUNT(*) result FROM T_Students t; -- result:32 rows
SELECT COUNT(1) result FROM T_Students t; -- result:32 rows

COUNT 是所有聚合函数中唯一不会忽略 NULL 值的函数,但如果被计算列本身含有 NULL 值是会被忽略的。示例如下:

SELECT COUNT(Remark) result FROM T_Students t; -- result:28 rows

在 COUNT 函数中添加 DISTINCT 参数,表示会先去除重复行,然后统计剩下的非 NULL 且唯一的值的个数。示例如下:

SELECT COUNT(DISTINCT Remark) result FROM T_Students t; -- result:26 rows

注意:COUNT 函数的返回值一定是大于或等于 0 的整数,证明如下:

SELECT COUNT(*) result;             -- result:1 rows
SELECT COUNT(*) result WHERE 1 = 2; -- result:0 rows

另外,从 SQL Server 2008 开始,官方在增加了一个COUNT_BIG函数,它的用法和用途与 COUNT 完全相同,唯一不同的就是返回值的类型。COUNT 函数总是返回一个 INT 类型的整数,而COUNT_BIG函数总是返回一个 BIGINT 类型的整数。示例如下:

SELECT COUNT_BIG(1) result FROM T_Students t;               -- result:32 rows
SELECT COUNT_BIG(Remark) result FROM T_Students t; -- result:28 rows
SELECT COUNT_BIG(DISTINCT Remark) result FROM T_Students t; -- result:26 rows

2.2、求和函数 SUM

求和函数 SUM 会返回表达式中所有值的和。SUM 函数会忽略所有 NULL 值,且只能应用于数字类型的字段。例如要查询学生 1 第 1 次考试的总分,示例如下:

SELECT SUM(t.Scores) FROM T_ExamResults t WHERE t.StudentId = 1 AND t.Counts = 1;

在 SUM 函数中添加 DISTINCT 参数,表示会先去除重复行,然后统计剩下的非 NULL 且唯一的数值之和。示例如下:

SELECT SUM(t.Scores) result FROM T_ExamResults t WHERE t.StudentId = 6;          -- result:2202.5
SELECT SUM(DISTINCT t.Scores) result FROM T_ExamResults t WHERE t.StudentId = 6; -- result:1857.5

注意:SUM 函数的返回值有可能会是 NULL 值,证明如下:

SELECT SUM(1) result;             -- result:1
SELECT SUM(1) result WHERE 1 = 2; -- result:NULL

2.3、求最大值函数 MAX

求最大值函数 MAX 会返回表达式中的最大值。MAX 函数会忽略所有 NULL 值。例如要查询学生 1 课程 1 的历次考试最高分,示例如下:

SELECT MAX(t.Scores) FROM T_ExamResults t WHERE t.StudentId = 1 AND t.Counts = 1;

MAX 函数还可以作用于日期类型或字符类型,此时 MAX 将按照日期数值或字符排序顺序来确定最大值。示例如下:

SELECT MAX(t.Birthday) FROM T_Students t; -- 数值最大的出生日期,年龄最小
SELECT MAX(t.Name) FROM T_Students t; -- 字符排序最靠后的姓名

注意:MAX 函数的返回值有可能会是 NULL 值,证明如下:

SELECT MAX(1) result;             -- result:1
SELECT MAX(1) result WHERE 1 = 2; -- result:NULL

2.4、求最小值函数 MIN

求最小值函数 MIN 会返回表达式中的最小值。MIN 函数会忽略所有 NULL 值。例如要查询学生 1 课程 1 的历次考试最低分,示例如下:

SELECT MIN(t.Scores) FROM T_ExamResults t WHERE t.StudentId = 1 AND t.Counts = 1;

MIN 函数还可以作用于日期类型或字符类型,此时 MAX 将按照日期数值或字符排序顺序来确定最小值。示例如下:

SELECT MIN(t.Birthday) FROM T_Students t; -- 数值最小的出生日期,年龄最大
SELECT MIN(t.Name) FROM T_Students t; -- 字符排序最靠前的姓名

注意:MIN 函数的返回值有可能会是 NULL 值,证明如下:

SELECT MIN(1) result;             -- result:1
SELECT MIN(1) result WHERE 1 = 2; -- result:NULL

2.5、求平均值函数 AVG

求平均值函数 AVG 会返回表达式中所有值的平均值。AVG 函数会忽略所有 NULL 值,且只能应用于数字类型的字段。例如要查询学生 1 第 1 次考试的平均分,示例如下:

SELECT AVG(t.Scores) FROM T_ExamResults t WHERE t.StudentId = 1 AND t.Counts = 1;

在 AVG 函数中添加 DISTINCT 参数,表示会先去除重复行,然后统计剩下的非 NULL 且唯一的数值之和。示例如下:

SELECT AVG(t.Scores) result FROM T_ExamResults t WHERE t.StudentId = 6;          -- result:73.416666
SELECT AVG(DISTINCT t.Scores) result FROM T_ExamResults t WHERE t.StudentId = 6; -- result:74.300000

注意:AVG 函数的返回值有可能会是 NULL 值,证明如下:

SELECT AVG(1) result;             -- result:1
SELECT AVG(1) result WHERE 1 = 2; -- result:NULL

2.6、聚合函数小结

上文逐一讲述了常见五大聚合函数的基本语法和用途。其实这些聚合函数不仅可以单独使用,还可以结合起来使用。

示例一、查询第 1 次课程 2 考试成绩的统计结果:

SELECT COUNT(1) 参与人数,
SUM(t.Scores) 总分,MAX(t.Scores) 最高分,MIN(t.Scores) 最低分,AVG(t.Scores) 平均分
FROM T_ExamResults t
WHERE t.Counts = 1 AND t.CourseId = 2;

示例二、查询 1 班的学生总数及年龄统计结果:

WITH t AS(
SELECT t.Code,t.Name,DATEDIFF(YEAR,t.Birthday,GETDATE()) Age
FROM T_Students t
WHERE t.ClassId = 1
)
SELECT COUNT(1) 学生个数,MAX(t.Age) 最大年龄,MIN(t.Age) 最小年龄,AVG(t.Age) 平均年龄
FROM t;

注意:本文所有关于聚合函数的示例,查询选择列表中包含的都是聚合函数表达式,没有一个字段,因为不允许,不过倒是可以包含与表字段无关的常量或变量。其实聚合函数通常与 GROUP BY 子句一起使用,而且也只有包含在 GROUP BY 子句中的字段才能出现在查询选择列表中,具体原因将在下一篇博文中具体讲述。

3、本文小结

本文主要讲述了 SQL Server 中的集合运算和聚合函数,以及它们的基本语法和用途。在集合运算中,UNION 和 UNION ALL 是比较常用的。而常见的 5 个聚合函数都比较常用。

本文参考链接:

去导航目录篇下载创建本系列博文通用库表及数据的 SQL 语句

本文链接http://www.cnblogs.com/hanzongze/p/tsql-aggregate.html

集合运算 & 聚合函数的更多相关文章

  1. SQL Server温故系列(4):SQL 查询之集合运算 & 聚合函数

    1.集合运算 1.1.并集运算 UNION 1.2.差集运算 EXCEPT 1.3.交集运算 INTERSECT 1.4.集合运算小结 2.聚合函数 2.1.求行数函数 COUNT 2.2.求和函数 ...

  2. Matlab的集合运算[转]

    今天遇到一个问题:有向量a和向量b,b是a的子向量(元素全部来自a),求向量a去掉向量b后剩下的元素构成的向量. 这么一个简单的问题,搜了半天也没有得到结果,因为找不到合适的关键词来描述这个问题. 在 ...

  3. Oracle组函数、多表查询、集合运算、数据库对象(序列、视图、约束、索引、同义词)等

    count组函数:(过滤掉空的字段) select count(address),count(*) from b_user max() avg() min(),sum() select sum(age ...

  4. 5_PHP数组_3_数组处理函数及其应用_9_数组集合运算函数

    以下为学习孔祥盛主编的<PHP编程基础与实例教程>(第二版)所做的笔记. 数组集合运算函数 1. array_merge() 函数 程序: <?php $array1 = array ...

  5. [SQL] SQL 基础知识梳理(七)- 集合运算

    SQL 基础知识梳理(七)- 集合运算 目录 表的加减法 联结(以列为单位) 一.表的加减法 1.集合:记录的集合(表.视图和查询的执行结果). 2.UNION(并集):表的加法 -- DDL:创建表 ...

  6. 第17课-数据库开发及ado.net 聚合函数,模糊查询like,通配符.空值处理.order by排序.分组group by-having.类型转换-cast,Convert.union all; Select 列 into 新表;字符串函数;日期函数

    第17课-数据库开发及ado.net 聚合函数,模糊查询like,通配符.空值处理.order by排序.分组group by-having.类型转换-cast,Convert.union all;  ...

  7. orm中的聚合函数,分组,F/Q查询,字段类,事务

    目录 一.聚合函数 1. 基础语法 2. Max Min Sum Avg Count用法 (1) Max()/Min() (2)Avg() (3)Count() (4)聚合函数联用 二.分组查询 1. ...

  8. SQL之开窗函数详解--可代替聚合函数使用

    在没学习开窗函数之前,我们都知道,用了分组之后,查询字段就只能是分组字段和聚合的字段,这带来了极大的不方便,有时我们查询时需要分组,又需要查询不分组的字段,每次都要又到子查询,这样显得sql语句复杂难 ...

  9. Task04:集合运算

    4.1 表的加减法 4.1.1 什么是集合运算 集合在数学领域表示"各种各样的事物的总和", 在数据库领域表示记录的集合. 具体来说,表.视图和查询的执行结果都是记录的集合, 其中 ...

随机推荐

  1. C语言利用fgetc复制拷贝文件内容

    #include <stdio.h> #include <stdlib.h> //文件的内容复制 int main(int a,char *argv[]){ if(a!=3){ ...

  2. leetcode解题报告(29):Student Attendance Record I

    描述 You are given a string representing an attendance record for a student. The record only contains ...

  3. loj #2053 莫队

    \(des\) 存在一个长度为 \(n\) 的数字 \(s\), 一个素数 \(P\) \(m\) 次询问一段区间 \([l, r]\) 内的子串构成的数是 \(P\) 的倍数 \(sol\) 对于一 ...

  4. Kindle Touch 修砖手札

    首先是网上的修砖教程: 最近有多人反映按照修砖程序走过后依然板砖,和碎平联系和WA沟通后对帖子作新的修改. 新教程直接使用5.1.2的镜像,特别说明. 特别感谢kn007的专业指导 小白帖子现为简化过 ...

  5. docker使用(一)

    windows家庭版 安装docker 查看原文地址(侵删,这里只是保存一用 doceker和vmware发生冲突时 运行下面命令并重启电脑: bcdedit /set hypervisorlaunc ...

  6. Subspace Subcode

    子码(subcode)的概念来自信息编码,不太容易理解.通常是子域编码(subfield subcode),也可以扩展到子空间编码(subspace subcode). 子空间或者子域编码的一个基本想 ...

  7. 贪心算法训练(九)——Best Cow Line(字典序最小问题)

    原题链接:Best Cow Line 1. 问题描述 2. 输入 6 A C D B C B 3. 输出 ABCBCD 4.思路分析 不断地取原字符串 S 中开头和末尾比较小的字符串放到 T 的末尾 ...

  8. SQLServer 使用自定义端口连接的方法(转载)

    使用过SQL Server的人大多都知道,SQL Server服务器默认监听的端口号是1433,但是我今天遇到的问题是我的机器上有三个数据库实例,这样使用TCP/IP远程连接时就产生了问题.如何在Mi ...

  9. fastdfs通过docker安装

    安装前准备 # yum install -y git #下载git # cd /data # mkdir fastdfs # cd fastdfs # git clone https://github ...

  10. Spatial-Temporal Relation Networks for Multi-Object Tracking

    Spatial-Temporal Relation Networks for Multi-Object Tracking 2019-05-21 11:07:49 Paper: https://arxi ...