参考教材《数据库系统:原理、设计与编程(MOOC版)》,陆鑫 张凤荔 陈安龙
终于到查询这一块了。
3.4 数据查询SQL语句
3.4.1 查询语句基本结构
SELECT [ALL/DISTINCT] <目标列>[,<目标列>...]
[INTO <新表>]
FROM <表名>[,<表名>...]
[WHERE <条件表达式>]
[GROUP BY <列名> [HAVING <条件表达式>]
ORDER BY <列名> [ASC/DESC]];
SELECT语句由多种字句组成:
- SELECT子句,用来指明从数据库表中需要查询的目标列。ALL是默认操作,获取所有满足条件的数据行;DISTINCT用来去掉结果集中的重复数据行;<目标列>为被查询表的指定列名,可以有多个。
- INTO子句,用来将被查询的结果集数据插入新表。
- FROM子句,用来指定被查询的数据来自哪个表或哪些表。多表用逗号分隔。
- WHERE子句,用来给出查询的检索条件,多个条件之间可以用AND、OR进行连接。
- GROUP BY子句,用来对查询结果进行分组,并进行分组统计等处理,在分组中,还可以使用HAVING关键词定义分组条件。
- ORDER BY子句,用来对查询结果集进行排序。ASC当然是升序,DESC是降序。默认为ASC。
从SELECT语句的操作结果看,<目标列>实现对关系表的投影操作,WHERE <条件表达式>实现对关系表的元组选择操作。
当前Student表的全部数据:
下面将会对该表进行一系列查询操作
3.4.2 从单表读取指定列
SELECT <目标列>[,<目标列>...]
FROM <表名>;
例3-19
-
从Student表中读取学生的学号、姓名、专业三列数据:
SELECT StudentID, StudentName, Major FROM Student; GO
-
从Student表中查询所有列数据:
SELECT * FROM Student; GO
-
只查Major数据:
SELECT Major FROM Student; GO
倘若只想查出不同的专业名称,可以消除重复行,用DISTINCT:
SELECT DISTINCT Major FROM Student; GO
3.4.3 从单表读取指定行
SELECT *
FROM <表名>
WHERE <条件表达式>;
例3-20
从Student表中读取专业为“软件工程”,性别为“男”的学生数据:
SELECT *
FROM Student
WHERE Major='软件工程' AND StudentGender='男';
GO
3.4.4 从单表读取指定行和列
SELECT <目标列> [,<目标列>...]
FROM <表名>
WHERE <条件表达式>;
例3-21
从Student表中读取专业为“软件工程”,性别为“男”的学生的学号、姓名、性别、专业四列的数据:
SELECT StudentID, StudentName, StudentGender, Major
FROM Student
WHERE Major='软件工程' AND StudentGender='男';
GO
3.4.5 WHERE子句条件
在WHERE
子句条件中,可以用BETWEEN...AND
关键词来限定列值范围,还可以用关键字LIKE
与通配符来限定查询范围,NOT LIKE
用于给出不在范围的条件。
SQL中常用通配符:
下划线(_):用于代表一个未指定的字符。
百分号(%):用于代表一个或多个未指定的字符。
例3-22
从Student表中查询出生日期在2000-01-01到2000-12-30的学生数据:
SELECT *
FROM Student
WHERE BirthDay BETWEEN '2000-01-01' AND '2000-12-30';
GO
还可以使用比较运算符完成相同操作:
SELECT *
FROM Student
WHERE BirthDay >= '2000-01-01' AND BirthDay <= '2000-12-30';
GO
在SQL中,除了'>='和'<='外,还有等于(=)、大于(>)、小于(<)、不等于(<>)等运算符。
例3-23
从Student表中查询姓氏为‘林’的学生数据:
SELECT *
FROM Student
WHERE StudentName LIKE '林%';
GO
查询专业名字中不带‘计算机’的学生数据:
SELECT *
FROM Student
WHERE Major NOT LIKE '计算机%';
GO
3.4.6 查询结果排序
查询的返回结果一般是按物理表中存放的顺序。可以在查询语句中使用ORDER BY
关键字进行排序。
例3-25
从Student表中按学生出生日期升序(ASC,默认)输出学生数据:
SELECT *
FROM Student
ORDER BY BirthDay;
GO
降序排序(DESC):
SELECT *
FROM Student
ORDER BY BirthDay DESC;
GO
以上是只给出单列进行SQL查询结果集排序,还可以同时按多列进行SQL查询结果集排序输出。
例3-26
从Student表中查询学生数据,先按专业名升序排列,再按出生日期降序排列:
SELECT *
FROM Student
ORDER BY Major ASC, BirthDay DESC;
GO
3.4.7 内置函数的使用
SQL中,可以使用函数方式对SELECT查询结果集数据进行处理。这些函数可以是DBMS所提供的内置函数,也可以使用户根据需要自定义的函数。
典型的DBMS提供的内置函数主要有:聚合函数、算术函数、字符串函数、日期时间函数、数据类型转换函数等。
-
聚合函数
又被称为统计函数,对表中的一些数据列进行计算并返回一个结果数值的函数。常用聚合函数如下:
注意,上表为PostgreSQL适用的聚合函数,在SQL Server中略有区别。
SQL Server的聚合函数:https://docs.microsoft.com/zh-cn/sql/t-sql/functions/aggregate-functions-transact-sql?view=sql-server-ver15例3-27
统计Student表中学生人数,在SELECT语句中使用COUNT()函数来计算:SELECT COUNT(*) FROM Student; GO
虽然查出了有10名同学,但结果集没有列名。可以用
AS
关键字对计算结果命名一个列名。SELECT COUNT(*) AS 学生人数 FROM Student; GO
以上查询语句使用
COUNT()
函数统计了数据表中所有元组的函数。使用COUNT()
还可以按指定列统计满足条件的元组行数。例3-28
统计Student表中的学生专业数目:SELECT COUNT(Major) AS 学生专业数 FROM Student; GO
显然上面的结果不是我们期待的结果,原因是查询统计中包含了若干相同专业的学生行,向同级不同专业数目,应当使用
DISTINCT
关键字消除结果集中的重复行,应当先DISTINCT再COUNT(),所以DISTINCT应该在COUNT()的括号内。SELECT COUNT(DISTINCT Major) AS 学生专业数 FROM Student; GO
例3-19
找出Student表中年龄最大的和年龄最小的学生的出生日期:SELECT MIN(BirthDay) AS 最大年龄出生日期, MAX(BirthDay) AS 最小年龄出生日期 FROM Student; GO
-
算术/数学函数
可使用算术/数学函数对数值型列进行算术运算操作。如果计算有效,返回一个计算结果值,否则返回NULL。常用算术/数学函数如下:
注意,上表为PostgreSQL适用的算数/数学函数,在SQL Server中略有区别。
SQL Server的算数/数学函数:https://docs.microsoft.com/zh-cn/sql/t-sql/functions/mathematical-functions-transact-sql?view=sql-server-ver15已有学生成绩表如下:
例3-30
当需要对成绩数据进行四舍五入处理时,可以使用ROUND()
算术函数处理:SELECT StudentID, StudentName, CourseName, ROUND(Grade, 0) AS Grade FROM Grade; GO
其中
ROUND(Grade, 0)
中的0应该是精度,四舍五入时精确到小数点后几位。 -
字符串函数
可用字符串函数对字符串表达式进行处理,这类函数输入的数据类型可以是字符串和数值类型,但输出为字符串类型。常用的字符串函数如下:
注意,上表为PostgreSQL适用的字符串函数,在SQL Server中略有区别。
SQL Server的字符串函数:https://docs.microsoft.com/zh-cn/sql/t-sql/functions/string-functions-transact-sql?view=sql-server-ver15例3-31
计算Student表中各个学生的Email字符串长度:SELECT StudentID, StudentName, Email, LEN(Email) AS 邮箱长度 FROM Student; GO
在处理字符串时,空格也是一个字符,要去掉空格,需要使用LTRIM()
、RTRIM()
等空格处理字符串。 -
日期时间函数
可用日期时间函数对日期、时间类型数据进行处理。输入数据为日期时间类型,输出结果可以是日期、时间、字符串或数值类型数据。常用的日期时间函数如下:
注意,上表为PostgreSQL适用的日期时间函数,在SQL Server中略有区别。
SQL Server的日期时间函数:https://docs.microsoft.com/zh-cn/sql/t-sql/functions/date-and-time-data-types-and-functions-transact-sql?view=sql-server-ver15例3-32
读取系统当前日期数据,然后分别显示系统日期的年、月、日数据。SELECT DATEPART(year, CURRENT_TIMESTAMP) AS 年, DATEPART(month,CURRENT_TIMESTAMP) AS 月, DATEPART(day, CURRENT_TIMESTAMP) AS 日; GO
-
数据类型转换函数
为了便于数据处理,SQL提供了不同数据类型之间的格式化转换函数。常用见下表:
注意,上表为PostgreSQL适用的数据类型转换函数,在SQL Server中略有区别。
SQL Server的数据类型转换函数:https://docs.microsoft.com/zh-cn/sql/t-sql/functions/conversion-functions-transact-sql?view=sql-server-ver15
差距有点大。例3-33
在Grade表中,Grade列数据类型为numeric(4,1),带有1位小数,将它转换为不带小数的2位字符输出:SELECT StudentID, StudentName, CourseName, CAST(Grade AS int) AS Grade FROM Grade; GO
可以看到成绩并没有四舍五入。进行四舍五入的操作后面再考虑,这里只是尝试一下数据类型转换函数。在SQL中,格式化函数吧各种数据类型转换成格式化字符串,以及反过来从格式化的字符串转换成指定的数据类型。这些函数都遵循一个公共调用习惯:第一个参数是待格式化的值,第二个参数是定义输出或输入格式的模板。具体操作见文档。
3.4.8 查询结果分组处理
内置函数通常可用于查询结果集的分组数据统计,可以通过在SELECT
语句中加入GROUP BY
子语句来实现。可以通过一定的规则将一个数据集划分为若干个组,然后针对每组数据进行统计运算处理。
例3-34
分专业统计Student表中的学生人数:
SELECT Major AS 专业, COUNT(StudentID) AS 学生人数
FROM Student
GROUP BY Major;
GO
还可以用HAVING
子句限定分组统计的条件。例如在统计各专业人数时,限定只显示人数大于3的专业人数:
SELECT Major AS 专业, COUNT(StudentId) AS 专业人数
FROM Student
GROUP BY Major
HAVING COUNT(*)>3;
GO
还可以同时使用HAVING
子句和WHERE
子句分别限定查询条件。应先使用WHERE过滤数据集,再使用HAVING限定分组数据。这个道理可以稍微思考一下。
例3-35
分专业统计Student表中男生人数,但限定只显示人数大于2的人数:
SELECT Major AS 专业, COUNT(StudentID) AS 学生人数
FROM Student
WHERE StudentGender='男'
GROUP BY Major
HAVING COUNT(*)>2;
GO
到这里可能会发现有的语句,比如WHERE
和HAVING
应该出现在什么位置,已经分不清了,这时候可以回文章头部看一下那个通用的SELECT
语句形式。
到现在为止一直说的是单表查询,多表查询会在下一篇再复习。