数据查询是数据库最经常使用的功能。在关系数据库中,查询操做是由SELECT语句来完成。其语法格式以下:算法
SELECT column_expression FROM table_name | view_name[,table_name | view_name, [,…]] [IN foreign_TABLE] [WHERE... ] [GROUP BY... ] [HAVING... ] [ORDER BY…] [With Owneraccess Option]
其中,column_expression为目标字段表达式,其语法格式为:数据库
[ALL|DISTINCT|TOP] * | table_name.* | [table_name.]column1_name[[AS] alias_name1]express
[, [table_name.] column2_name [ [AS] alias_name2] [, ...]]函数
SELECT语句的主要做用是,从FROM子句指定的数据表或者视图中找出知足WHERE子句设定的条件的元组,并按照SELECT子句指定的目标字段表达式从新组织这些元组,从而造成新的结果集。若是没有WHERE子句,则默认选出全部的元组。post
如下主要按子句功能来介绍SELECT语句的使用方法,若是不特别说明,则均指基于表5.10所示的数据表student进行查询。大数据
【例子】 为了能看到下文介绍的SELECT语句的执行效果,在用CREATE TABLE语句建立数据表student之后,请接着在SSMS中执行下列的INSERT语句,以在数据库中建立与表5.10所示内容彻底同样的数据表:spa
INSERT student VALUES('20170201','刘洋','女','1997-02-03','计算机应用技术',98.5,'计算机系');设计
INSERT student VALUES('20170202','王晓珂','女','1997-09-20','计算机软件与理论',88.1,'计算机系');code
INSERT student VALUES('20170203','王伟志','男','1996-12-12','智能科学与技术',89.8,'智能技术系');blog
INSERT student VALUES('20170204','岳志强','男','1998-06-01','智能科学与技术',75.8,'智能技术系');
INSERT student VALUES('20170205','贾簿','男','1994-09-03','计算机软件与理论',43.0,'计算机系');
INSERT student VALUES('20170206','李思思','女','1996-05-05','计算机应用技术',67.3,'计算机系');
INSERT student VALUES('20170207','蒙恬','男','1995-12-02','大数据技术',78.8,'大数据技术系');
INSERT student VALUES('20170208','张宇','女','1997-03-08','大数据技术',59.3,'大数据技术系');
基本查询是指基于单表(一个数据表或视图)的仅仅由SELECT子句和FROM子句构成的SELECT语句。其通常格式以下:
SELECT [ALL|DISTINCT|TOP] * | table_name.* | [table_name.]column1_name[ [AS] alias_name1] [, [table_name.] column2_name [ [AS] alias_name2] [, ...]]
FROM table_name;
因为视图的查询与数据表的查询是同样的,如下仅考虑数据表的查询问题。对于视图的查询能够由此推广。
有时候但愿查询结果包含全部的字段,这时只需将目标字段表达式设定为星号“*”便可,也能够列出全部的字段。
【例子】 下列的SELECT语句实现的就是最简单的基本查询,其结果将包含全部字段的所有数据元组:
SELECT * FROM student;
该语句等价于下列的SELECT语句:
SELECT s_no,s_name,s_sex,s_birthday,s_speciality,s_avgrade,s_dept
FROM student;
在不少状况下,用户仅对表中的某些字段感兴趣,而且但愿这些字段可以按照指定的顺序列出。
【例子】 查询全体学生的平均成绩和姓名(平均成绩在前,姓名在后)。
SELECT s_avgrade,s_name
FROM student;
执行后结果以下:
s_avgrade s_name
------------------------
98.5 刘洋
88.1 王晓珂
89.8 王伟志
75.8 岳志强
43.0 贾簿
67.3 李思思
78.8 蒙恬
59.3 张宇
每一字段都是用字段名来“标识”(字段名通常为英文),例如,第一字段标识为“s_avgrade”,第二字段标识为“s_name”。
这对中国用户来讲并不方便,可使用带关键子AS的目标字段表达式来解决,其中AS后面跟由用户指定的字段标题(关键字AS能够省略)。
【例子】 对于上述问题,可用下列的语句来完成:
SELECT s_avgrade AS 平均成绩, s_name AS 姓名 -- AS也能够省略
FROM student;
执行后结果以下:
平均 成绩姓名
------------------------
98.5 刘洋
88.1 王晓珂
89.8 王伟志
75.8 岳志强
43.0 贾簿
67.3 李思思
78.8 蒙恬
59.3 张宇
查询结果中的计算字段(列)是指根据数据表中的某一个或者若干个字段进行计算而获得的新字段,并把它放在查询结果集中,实际上在数据表中并不存在此字段。
【例子】 要求查询全体学生的姓名和年龄。因为数据表student中没有年龄这一字段,而仅有与之相关的出生日期(birthday)这一字段。必须通过出生日期来计算每一个学生的年龄,相应的SQL语句以下:
SELECT s_name 姓名, Year(getdate())-Year(s_birthday) 年龄
FROM student;
用到两个系统函数:getdate()和Year(),它们分别用于获取datetime类型的系统时间和时间的年份。
上述语句执行的结果以下:
姓名 年龄
-----------------------
刘洋 20
王晓珂 20
王伟志 21
岳志强 19
贾簿 23
李思思 21
蒙恬 22
张宇 20
使用SELECT查询时,SELECT后面可加上下字段关键字,以知足不一样的查询要求:
ALL:ALL是默认关键字,即当不加任何关键字时,表示默认使用ALL做为关键字。它表示要返回全部知足条件的元组。前面介绍的查询正是这种查询。
TOP:有两种格式:TOP n和TOP n PERCENT。第一种格式表示返回前面n个元组,而第二种格式则表示返回前面n%个元组;若是n%不是整数,则向上取整。
DISTINCT:若是带此关键字,则在查询结果中若包含重复记录(行),则只返回这些重复元组中的一条。即关键字DISTINCT保证了查询结果集中不会包含重复元组,但与DISTINCTROW不同的是它不会删除全部的重复元组。
【例5.6】 查询表student中涉及的不一样的系别信息。
该查询要求可用下列的语句完成:
SELECT DISTINCT s_dept 所在的系
FROM student;
执行后结果以下:
所在的系
-----------------
大数据技术系
计算机系
智能技术系
若是在以上语句中不加上关键字DISTINCT,则返回下列结果:
所在的系
-----------------
计算机系
计算机系
智能技术系
智能技术系
计算机系
计算机系
大数据技术系
大数据技术系
从以上不难看出关键字DISTINCT的做用。若是DISTINCT后面跟有多个字段名,则DISTINCT必须放在第一字段名的前面(即紧跟SELECT以后),而不能放在其余字段名的前面。
【例子】 下列的语句是正确的。
SELECT DISTINCT s_dept, s_sex
FROM student;
而下面的语句则是错误的:
SELECT s_dept, DISTINCT s_sex
FROM student;
【例5.7】 查询表student中前3条记录,列出它们全部的字段信息。
该查询可用带关键字TOP来实现:
SELECT TOP 3 *
FROM student;
若是用下列语句,虽然8*38% = 3.04,但因为采起向上取整,其结果返回4条记录:
SELECT TOP 38 PERCENT *
FROM student;
在实际应用中,更多时候是根据必定条件来进行查询的,即查询知足必定条件的部分记录(而不是表中的全部记录)。WHERE子句将发挥做用,其通常语法格式以下:
SELECT column_expression FROM table_name WHERE condition_expression
condition_expression是条件表达式,一般称为查询条件。查询条件就是一种逻辑表达式,只有那些使该表达式的逻辑值为真的记录才按照目标字段表达式column_expression指定的方式组成一个新记录而添加到结果集中。
查询条件是一种逻辑表达式,就能够用一些逻辑联结联结词来构建这种表达式。经常使用联结词包括NOT、OR、AND等,分别表示逻辑意义上的“非”、“或”和“与”。
【例5.8】 要求查询表student中平均成绩为良好(80~90,但不等于90)的学生的学号、姓名、性别和平均成绩。
对于这一查询要求,可用下列的SELECT语句:
SELECT s_no 学号,s_name 姓名,s_sex 性别, s_avgrade 平均成绩
FROM student
WHERE s_avgrade>=80 AND s_avgrade<90;
该语句执行后结果以下:
学号 姓名 性别 平均成绩
-------------------------------------------------------------
20170202 王晓珂 女 88.1
20170203 王伟志 男 89.8
WHERE子句虽然语法格式比较简单,但在查询中倒是使用得最多。下面介绍的查询大多都会涉及到WHERE子句,读者应该深入领会其使用方法。
有时候须要查询哪些字段值在必定范围内的记录,这时可使用带BETWEEN的查询语句。其语法格式为:
SELECT column_expression FROM table_name WHERE column_name [NOT] BETWEEN value1 AND value2;
value1和value2都是字段column_name的具体值,且value1≤value2。该语句的查询结果是返回全部字段column_name的值落在value1到value2(包括value1和value2)之间范围内的记录。
【例5.9】 要求查询全部出生在1996年08月01日到1997年10月01日之间(包括这两个日期)的学生,并将他们的姓名、性别、系别、平均成绩以及出生年月列出来。
对于这个查询要求,能够用下列的语句完成:
SELECT s_name 姓名, s_sex 性别, s_dept 系别, s_avgrade 平均成绩,s_birthday 出生年月 FROM student WHERE s_birthday BETWEEN '1996-08-01' AND '1997-10-01’;
执行后结果以下:
姓名 性别 系别 平均成绩 出生年月
---------------------------------------------------------------------------------------------------
刘洋 女 计算机系 98.5 1997-02-03
王晓珂 女 计算机系 88.1 1997-09-20
王伟志 男 智能技术系 89.8 1996-12-12
张宇 女 大数据技术系 59.3 1997-03-08
若是要查询字段column_name的值不落在value1到value2(包括不等于value1和value2)之间的全部记录,则只需在相应的BETWEEN前加上谓词NOT便可。
例如,上例中查询不是出生在1996年08月01日到1997年10月01日之间的学生,可用下列的语句:
SELECT s_name 姓名, s_sex 性别, s_dept 系别, s_avgrade 平均成绩,s_birthday 出生年月 FROM student WHERE s_birthday NOT BETWEEN '1996-08-01' AND '1997-10-01’;
执行结果以下:
姓名 性别 系别 平均成绩 出生年月
------------------------------------------------------------------------------------------------
岳志强 男 智能技术系 75.8 1998-06-01
贾簿 男 计算机系 43.0 1994-09-03
李思思 女 计算机系 67.3 1996-05-05
蒙恬 男 大数据技术系 78.8 1995-12-02
BETWEEN只适合于字段值为数值型的状况。
IN与BETWEEN具备相似的功能,都是查询知足字段值在必定范围内的记录。但与BETWEEN不一样的是,IN后面必须跟枚举的字段值表(字段值的枚举),即把全部的字段值都列出来,而不能写为“value1 AND value2”的形式。这至关于在一个集合中进行查询,适合于那些不是数值型的状况。其语法格式为:
SELECT column_expression FROM table_name WHERE column_name [NOT] IN (value1, value2, …, valuen)
【例5.10】 要求查询智能技术系和大数据技术系的学生。
对于这个查询要求,能够用下列的语句来实现:
SELECT s_no 学号, s_name 姓名, s_sex 性别, s_birthday 出生年月, s_speciality 专业, s_avgrade 平均成绩, s_dept 系别 FROM student WHERE s_dept IN ('智能技术系','大数据技术系')
相应的输出以下:
学号 姓名 性别 出生年月 专业 平均成绩 系别
----------------------------------------------------------------------------------------------------------------------------------------------
20170203 王伟志 男 1996-12-12 智能科学与技术 89.8 智能技术系
20170204 岳志强 男 1998-06-01 智能科学与技术 75.8 智能技术系
20170207 蒙恬 男 1995-12-02 大数据技术 78.8 大数据技术系
20170208 张宇 女 1997-03-08 大数据技术 59.3 大数据技术系
实际上,“column_name IN (value1, value2, …, valuen)” 等价“column_name=value1 OR column_name=value2 OR…OR column_name=valuen”。
上例的查询语句也等价于:
SELECT s_no 学号, s_name 姓名, s_sex 性别, s_birthday 出生年月, s_speciality 专业, s_avgrade 平均成绩, s_dept 系别 FROM student WHERE s_dept='智能技术系' OR s_dept='大数据技术系';
这种IN的语句比带OR的语句在结构上比较简洁和直观。
另外,与BETWEEN相似,对于字段值不在(value1, value2, …, valuen)中的查询,可经过在IN以前加上NOT来实现。
带GROUP的查询就是一般所说的分组查询,它将查询结果按照某一字段或某一些字段的字段值进行分组。咱们就能够对每一组进行相应的操做,而通常的查询(如上面介绍的查询)都只能针对每一条记录进行操做。
用于统计每一组的记录个数。如下是分组查询的语法格式:
SELECT column_expression[, count(*)] FROM table_name GROUP BY column_expression [HAVING condition_expression]
HAVING是可选的,它用于对造成的分组进行筛选,留下知足条件condition_expression的组。
【例5.11】 要求查询表student中各系学生的数量。
(1)对于此查询,要按系(s_dept)来实现分组,相应的语句以下:
SELECT s_dept 系别, count(*) 人数 FROM student GROUP BY s_dept;
查询结果以下:
系别 人数
--------------------------------
大数据技术系 2
计算机系 4
智能技术系 2
(2)若是要查询人数大于或等于2的系的学生数量分布状况(每一个系有多少人),则能够用HAVING短语来实现。
SELECT s_dept 系别, count(*) 人数 FROM student GROUP BY s_dept HAVING count(*) >= 2;
(3)若是进一步要求在平均成绩及格(s_avgrade >= 60)的学生中完成这种分组查询,即对于平均成绩及格的学生,若是要查询他们人数大于或等于2的系的学生数量分布状况,则能够先用WHERE子句来选择及格的学生,而后用HAVING短语来实现分组查询:
SELECT s_dept 系别, count(*) 人数 FROM student WHERE s_avgrade >= 60 GROUP BY s_dept HAVING count(*) >= 2
执行结果以下:
系别 人数
-------------------------
计算机系 3
智能技术系 2
注意:WHERE子句应该在GROUP和HAVING以前出现。
注意:WHERE子句和HAVING短语的做用都同样,都是用于指定查询条件。它们是有区别的:
HAVING短语是用于对组设定条件,而不是具体的某一条记录,从而使得SELECT语句能够实现对组进行筛选;
WHERE子句是对每一条记录设定条件的,而不是一个记录组。
模糊查询在大多状况下都是由谓词LIKE来实现。其通常语法格式为:
SELECT column_expression FROM table_name WHERE column_name [NOT] LIKE character_string;
column_name的类型必须是字符串类型,character_string表示字符串常数。
该语句的含义是查找字段column_name的字段值与给定字符串character_string相匹配的记录。
字符串character_string能够是一个字符串常量,也能够是包含通配符“_”和“%”的字符串。是否相匹配要根据下列原则来肯定:
“_”(下划线): 它能够与任意的单字符相匹配。
“%”(百分号) :它能够与任意长度字符串(包括空值)相匹配。
除了字符“_”和“%”外,全部其它的字符都只能匹配本身。
【例5.12】 查询全部姓“王”的学生,并列出他们的学号、姓名、性别、平均成绩和系别。
SELECT s_no 学号,s_name 姓名,s_sex 性别,s_avgrade 平均成绩,s_dept 系别 FROM student WHERE s_name LIKE '王%';
该语句的查询结果以下:
学号 姓名 性别 平均成绩 系别
---------------------------------------------------------------------------------
20170202 王晓珂 女 88.1 计算机系
20170203 王伟志 男 89.8 智能技术系
这是由于字符串'王%'能够与任何第一个字为“王”的名字相互匹配。若是谓词LIKE后跟'王_',则只能找出任何王姓且姓名仅由两个字组成的学生;若是谓词LIKE后跟'%志%',则表示要找出姓名中含有“志”的学生。
注意,因为字段s_name的数据类型是固定长度的8个字符(char(8)),所以若是s_name值的实际长度不够8个字符的,则后面以空格填补。
空值null的查询是指查找指定字段的字段值为null的记录。对于这种查询,首先想到的方法可能就是用带等号“=”的WHERE子句来实现。但这种查找方法是失败的。
例如,下列的SELECT语句将找不到任何的记录,即便存在s_avgrade的字段值为null的记录:
SELECT * FROM student WHERE s_avgrade = null -- 错误
而正确的写法应该是:
SELECT * FROM student WHERE s_avgrade IS null -- 正确
【例5.13】 查找全部字段s_avgrade的值为非空的记录。
SELECT * FROM student WHERE s_avgrade IS NOT null
有时候咱们但愿将查询结果按照必定的顺序进行排列,以方便、快速地从结果集中获取咱们须要的信息。
例如,按照学生的成绩从高到低进行排序,这样咱们一眼就能够看出谁的分数最高、谁的最低。而带ORDER BY子句的SELECT语句就能够实现对查询结果进行排序。其通常语法格式以下:
SELECT column_expression FROM table_name ORDER BY column_name [ASC|DESC][,…]
column_name表示排序的依据字段,ASC表示按依据字段进行升序排列,DESC表示按依据字段进行降序排列。若是ASC和DESC都没有选择,则按依据字段进行升序排列,即ASC为默认值。
【例5.14】 对表student中的男同窗按成绩进行降序排序。
SELECT * FROM student WHERE s_sex = '男' ORDER BY s_avgrade DESC
执行后结果以下:
学号 姓名 性别 出生日期 专业 平均成绩 系别
---------------------------------------------------------------------------------------------------------------------------------------
20170203 王伟志 男 1996-12-12 智能科学与技术 89.8 智能技术系
20170207 蒙恬 男 1995-12-02 大数据技术 78.8 大数据技术系
20170204 岳志强 男 1998-06-01 智能科学与技术 75.8 智能技术系
20170205 贾簿 男 1994-09-03 计算机软件与理论 43.0 计算机系
【例子】 若是但愿在成绩相同的状况下,进一步按照学号进行升序排列,则能够经过在ORDER BY后面增长字段s_no的方法来实现。相应的语句以下:
SELECT * FROM student WHERE s_sex = '男' ORDER BY s_avgrade DESC, s_no ASC
在上面的语句中,排序的原理是这样的:首先按照平均成绩对记录进行降序排序(由于选择了DESC);若是查询结果包含有平均成绩相同的记录,那么这时按平均成绩就没法对这些具备相同平均成绩的记录进行排序,这时SELECT语句将自动按照下一字段——学号(s_no)对这些记录进行升序排序(升序是默认排序方式);若是s_no后面还有其余字段,那么排序原理也依次类推。
同时涉及到两个或者两个以上数据表的查询称为链接查询。链接查询能够找出多个表之间蕴涵的有用信息,实际上它是关系数据库中最主要的查询。链接查询主要包括等值链接查询、天然链接查询、外链接查询以及交叉链接查询等。但交叉链接查询没有实际意义,且运用的不多,在此不做介绍。
链接查询涉及到两种表。除了表5.10所示的数据表student之外,咱们还需建立另外一张数据表——选课表SC。该表的结构和内容分别如表5.11和表5.12所示。
先用下列语句建立选课表SC:
CREATE TABLE SC( s_no char(8), c_name varchar(20), c_gradenumeric(3,1) CHECK(c_grade >= 0 AND c_grade <= 100), PRIMARY KEY(s_no, c_name) --将(s_no, c_name)设为主键 );
而后用下列INSERT插入如表5.12所示的数据,以便观察链接查询的效果:
INSERT SC VALUES('20170201','英语',80.2); INSERT SC VALUES('20170201','数据库原理',70.0); INSERT SC VALUES('20170201','算法设计与分析',92.4); INSERT SC VALUES('20170202','英语',81.9); INSERT SC VALUES('20170202','算法设计与分析',85.2); INSERT SC VALUES('20170203','多媒体技术',68.1);
不特别说明,在本节中介绍的链接查询主要是基于表student和表SC进行的。
在使用链接查询时,按照必定的条件在两个或多个表中提取数据并组成新的记录,全部这些记录的集合便构成了一个新的关系表。那么这个条件就称为链接条件,表示为join_condition。链接条件具备下列的形式:
[table1_name.]columni_name comp_oper [table2_name.]columnj_name
其中,comp_oper表示比较操做符,主要包括=、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)、!=(不等)。链接条件有意义的前提是字段column1_name和column2_name是可比较的。
当链接条件的比较操做符comp_oper为等号“=”时,相应的链接就称为等值链接。对于表table1_name和表table2_name之间的等值链接,其通常格式能够表示以下:
SELECT [table1_name.]column1_name[, …], [table2_name.]column1_name[, …] FROM table1_name, table2_name WHERE [table1_name.]columni_name = [table2_name.]columnj_name
注意,对于字段名前面的表名是否须要显式标出,这取决于两个表中是否都有与此同名的字段。若是有,则必须冠以表名,不然能够不写表名。
链接条件中相互比较的两个字段必须是可比的,不然比较将无心义。但可比性并不意味着两个字段的数据类型必须同样,而只要求它们在语义上可比便可。
【例子】 对于整型的字段和浮点型的字段,虽然数据类型不一样,但它们倒是可比的;而将整型的字段和字符串型的字段进行比较,那是无心义的。
对于链接操做,能够这样来理解:首先取表table1_name中的第一条记录,而后从表table2_name中的第一条记录开始依次扫描全部的记录,并检查表table1_name中的第一条记录与表table2_name中的当前记录是否知足查询条件,若是知足则将这两条记录并接起来,造成结果集中的一条记录。当对表table2_name扫描完了之后,又从表table1_name中的第二条记录开始,重复上面相同的操做,直到表table1_name中全部的记录都处理完毕为止。
【例5.15】 要求查询选课学生的学号、姓名、性别、专业、系别以及所选的课程名称和成绩。
这个查询要求就涉及到两个表的查询,由于学生的基本信息包含在表student中,而选课信息则包含在表SC中。一个学生是否选课能够这样获知:若是表SC中有他的学号,则代表该学生已经选课,不然没有选课。上述查询问题就能够表述为,扫描表student和表SC中的每一条记录,若是这两个表中的当前记录在各自的字段s_no上取值相等,则将这两条记录按照指定的要求并接成一个新的记录并添加到结果集中。这种查询是以表student中的字段s_no和表SC中的字段s_no是否相等为查询条件的,因此这种查询就是等值查询。该等值查询的实现语句以下:
SELECT student.s_no 学号, s_name 姓名, s_sex 性别, s_speciality 专业, s_dept 系别, c_name 课程名称, c_grade 课程成绩 FROM student, SC WHERE student.s_no = SC.s_no
执行后的结果以下:
学号 姓名 性别 专业 系别 课程名称 课程成绩
---------------------------------------------------------------------------------------------------------------------------------------
20170201 刘洋 女 计算机应用技术计算机系 数据库原理 70.0
20170201 刘洋 女 计算机应用技术计算机系 算法设计与分析 92.4
20170201 刘洋 女 计算机应用技术计算机系 英语 80.2
20170202 王晓珂 女 计算机软件与理论计算机系 算法设计与分析 85.2
20170202 王晓珂 女 计算机软件与理论计算机系 英语 81.9
20170203 王伟志 男 智能科学与技术智能技术系 多媒体技术 68.1
表student和表SC中都有字段s_no,必须在其前面冠以表名,以明确s_no是属于哪个表中的字段。若是在涉及的两个表中还有其余同名的字段,也需进行一样的处理。
若是以为表名过长,使用起来比较麻烦,则能够利用AS来定义别名,经过使用别名来进行表的链接查询。
【例子】 上述的等值链接查询语句跟下面的查询语句是等价的:
SELECT a.s_no 学号, s_name 姓名, s_sex 性别, s_speciality 专业, s_dept 系别, c_name 课程名称, c_grade 课程成绩 FROM student as a, SC as b WHERE a.s_no = b.s_no
上述SELECT语句中,利用AS将表名student和SC分别定义为a和b,而后经过a和b来进行链接查询,从而简化代码。
若是在上述的等值链接查询语句中去掉WHERE子句,则获得下列的SELECT语句:
SELECT student.s_no 学号, s_name 姓名, s_sex 性别, s_speciality 专业, s_dept 系别, c_name 课程名称, c_grade 课程成绩 FROM student, SC
该语句将造成表student和表SC的笛卡儿积。笛卡儿积是将两个表中的每一条记录分别并接而获得的结果集。笛卡儿积中记录的条数是两个表中记录条数的乘积,
天然链接其实是一种特殊的等值链接,这种链接在等值链接的基础上增长如下两个条件而造成的:
(1)参加比较的两个字段必须是相同的,即同名同类型;
(2)结果集的字段是参加链接的两个表的字段的并集,但去掉了重复的字段。
【例5.16】 实现表student和表SC的天然链接查询。
可用下列的SELECT语句来实现:
SELECT student.s_no 学号, s_name 姓名, s_sex 性别, s_birthday 出生日期, s_speciality 专业, s_avgrade 平均成绩,s_dept 系别, c_name 课程名称, c_grade 课程成绩 FROM student, SC WHERE student.s_no = SC.s_no
上述语句执行获得的天然链接结果如表5.13所示。
该结果集中的字段包含了表student和表SC中全部的字段,并去掉了重复字段SC.s_no而保留student.s_no(固然,也能够去掉student.s_no而保留SC.s_no),并且无其余重复字段,因此该等值查询是天然链接查询。
以上介绍的都是基于两个不一样的表进行链接查询。但有时候须要将一个表跟它自身进行链接查询,以完成相应的查询任务,这种查询就称为自链接查询。
在使用自链接查询时,虽然实际操做的是同一张表,但在逻辑上要使之分为两张表。这种逻辑上的分开能够在SQL Server中经过定义表别名的方法来实现,即为一张表定义不一样的别名,这样就造成了有相同内容、但表名不一样的两张表。
【例5.17】 要求查询表student中与“刘洋”在同一个专业的全部学生的学号、姓名、性别、专业和平均成绩(包括“李好”)。
这种查询的难处在于,咱们不知道“刘洋”的专业是什么,若是知道了她的专业,那么该查询就很容易实现。必须从姓名为“刘洋”的学生记录中得到她的专业,而后由专业获取相关学生的信息。这种查询难以用单表查询来实现。若是使用自链接查询,那么问题就很容易获得解决。
自链接查询的方法以下:为表student建立一个别名b,这样student和b便造成逻辑上的两张表。而后经过表student和表b的链接查询实现本例的查询任务。但这种自链接查询要用到JOIN…ON…子句。查询语句以下:
SELECT b.s_no 学号, b.s_name 姓名, b.s_sex 性别,b.s_speciality 专业, b.s_avgrade 平均成绩 FROM student AS a-- 为student建立别名a JOIN student AS b -- 为student建立别名b ON (a.s_name='刘洋' AND a.s_speciality = b.s_speciality);
该语句运行结果以下:
学号 姓名 性别 专业 平均成绩
--------------------------------------------------------------------------
20170201刘洋 女 计算机应用技术 98.5
20170206李思思 女 计算机应用技术 67.3
定义student的一个别名也能够实现此功能:
SELECT b.s_no 学号, b.s_name 姓名, b.s_sex 性别,b.s_speciality 专业, b.s_avgrade 平均成绩 FROM student JOIN student AS b -- 为student建立别名b ON (student.s_name='刘洋' AND student.s_speciality = b.s_speciality);
上述介绍的链接查询中,只有那些知足查询条件的记录才被列出来,而不知足条件的记录则“不翼而飞”,这在有的应用中并不合适。
例如,在对表student和表SC进行等值链接查询后,学号为“20120204”等学生因为没有选课,因此在查询结果中就没有关于这些学生的信息。可是不少时候咱们但愿可以将全部学生信息所有列出,对于没有选课的学生,其对应课程字段和课程成绩字段留空便可。上述链接查询方法就不适用了,须要引进另外一种链接查询——外链接查询。
外链接查询的语法格式为:
SELECT [table1_name.]column1_name[, …], [table2_name.]column1_name[, …] FROM table1_name LEFT|RIGHT [OUTER] JOIN table2_name ON join_condition
若是在FROM子句中选择关键字LEFT,则该查询称为左外链接查询;若是选择关键字RIGHT,则该查询称为右外链接查询。
在左外链接查询中,对于表table1_name(左边的表)中的记录无论是否知足链接条件join_condition,它们都将将被列出;而对表table2_name(右边的表)中的记录,只有知足链接条件join_condition的部分才被列出。
在右外链接查询中,对于表table2_name中的记录无论是否知足链接条件join_condition,它们都将将被列出;而对表table1_name中的记录,只有知足链接条件join_condition的部分才被列出。
【例5.18】 查询全部学生的基本信息,若是他们选课了则同时列出相应的课程信息(含姓名、性别、专业、系别以及课程名称和课程成绩)。
这种查询的基本要求是,首先无条件地列出全部学生相关信息;其次对于已经选课的学生,则列出其相应的选课信息,而对于没有选课的学生,其相应的字段留空。即表student中的记录要无条件列出,而表SC中的记录只有知足链接条件(已选课)的部分才能列出。这须要用外链接查询来实现,其实现语句以下:
SELECT s_name 姓名, s_sex 性别, s_speciality 专业, s_dept 系别, SC.c_name 课程名称, SC.c_grade 课程成绩 FROM student
LEFT JOIN SC ON (student.s_no = SC.s_no);
以上采用的是左外链接查询。也能够将表student和表SC的位置调换一下,改用右外链接查询,其实现语句以下:
SELECT s_name 姓名, s_sex 性别, s_speciality 专业, s_dept 系别, SC.c_name 课程名称, SC.c_grade 课程成绩 FROM SC RIGHT JOIN student ON (student.s_no = SC.s_no);
以上两种外链接查询语句的做用都是同样的,执行后都获得以下结果:
姓名 性别 专业 系别 课程名称 课程成绩
----------------------------------------------------------------------------------------------------------------------------
刘洋 女计算机应用技术计算机系 数据库原理70.0
刘洋 女计算机应用技术计算机系 算法设计与分析92.4
刘洋 女计算机应用技术计算机系 英语80.2
王晓珂 女计算机软件与理论计算机系 算法设计与分析85.2
王晓珂 女计算机软件与理论计算机系 英语81.9
王伟志 男智能科学与技术智能技术系 多媒体技术68.1
岳志强 男智能科学与技术智能技术系 NULLNULL
贾簿 男计算机软件与理论计算机系 NULLNULL
李思思 女计算机应用技术计算机系 NULLNULL
蒙恬 男大数据技术大数据技术系 NULLNULL
张宇 女大数据技术大数据技术系 NULLNULL
从以上结果能够看出,“岳志强”等虽然没有选课,但他们的基本信息仍是被列出了,其相应显示选课信息的位置则留空(NULL)。
一个查询A能够嵌入到另外一个查询B的WHERE子句中或者HAVING短语中,由这种嵌入方法而获得的查询就称为嵌入查询。查询A称为查询B的子查询(或内层查询),查询B称为查询A的父查询(或外层查询、主查询等)。
观察下面的例子:
SELECT s_no,s_name -- FROM student ----父查询 WHERE s_no IN( -- SELECT s_no -- FROM SC ----子查询 WHERE c_name = '算法设计与分析') --
该查询就是一个嵌套查询,它找出了选“算法设计与分析”这门课的学生的学号和姓名。其中,括号内的查询为子查询,括号外的查询为父查询。子查询还能够嵌套其余的子查询,即SQL语言容许多层嵌套查询。
执行嵌套查询的过程:首先执行最内层的子查询,而后用子查询的结果构成父查询的WHERE子句,并执行该查询;父查询产生的结果又返回给其父查询的WHERE子句,其父查询又执行相同的操做,直到最外层查询执行完为止。也就是说,嵌套查询的执行过程是由里向外。
嵌套查询的优势是,每一层的查询都是一条简单的SELECT语句,其结构清晰,易于理解。但不能对子查询的结果进行排序,即子查询不能带ORDER BY子句。
如下将根据所使用谓词的不一样来介绍各类嵌套查询,而且假设讨论的嵌套查询是由子查询和父查询构成。对于多层的嵌套查询,不难由此推广。
带IN的嵌套查询是指父查询和子查询是经过谓词IN来链接的一种嵌套查询,也是用得最多的嵌套查询之一。其特色是,子查询的返回结果被看成是一个集合,父查询则判断某一字段值是否在该集合中,以肯定是否要输出该字段值对应的记录的有关信息。
【例5.19】 查询“王伟志”和“蒙恬”所在专业的全部学生信息。
这个查询的解决过程是,首先找出他们所在的专业,而后根据专业来查找学生。为此能够分为两步走。
首先肯定“王伟志”和“蒙恬”所在的专业:
SELECT student.s_speciality FROM student WHERE student.s_name = '王伟志' OR student.s_name = '蒙恬‘
上述语句的返回结果是('智能科学与技术', '大数据技术')。下一步要作的就是查找全部专业为智能科学与技术或大数据技术的学生。相应的SELECT语句以下:
SELECT * FROM student WHERE student.s_speciality IN ('智能科学与技术', '大数据技术');
将中间结果(‘智能科学与技术’, ‘大数据技术’)去掉,代之以产生该结果的SELECT语句,因而获得了下列的嵌套查询:
SELECT * FROM student WHERE student.s_speciality IN ( SELECT student.s_speciality FROM student WHERE student.s_name = '王伟志' OR student.s_name = '蒙恬');
执行该嵌套查询后获得以下的结果,该结果与咱们预想的彻底一致:
s_nos_names_sexs_birthday s_speciality s_avgrade s_dept
------------------------------------------------------------------------------------------------------------------------------
20170203王伟志 男1996-12-12 智能科学与技术89.8智能技术系
20170204岳志强 男1998-06-01 智能科学与技术75.8智能技术系
20170207蒙恬 男1995-12-02 大数据技术 78.8大数据技术系
20170208张宇 女1997-03-08 大数据技术 59.3大数据技术系
对于这个例子,若是运用链接查询,会显得比较复杂。但使用带IN的嵌套查询,无论在问题的解决思路上仍是在SELECT语句的构造上都显得更具条理性和直观性,并且仅涉及到一个逻辑表(不用建立别名)。
比较运算符是指>、<、=、>=、<=、<>等符号。这些符号能够将一个字段与一个子查询链接起来构成一个逻辑表达式。以这个逻辑表达式为查询条件的查询就构成了父查询。
通常来讲,这种比较只能是基于单值进行的,因此要求子查询返回的结果必须为单字段值。
能够返回('智能科学与技术'),但返回('智能科学与技术', '大数据技术')则是不容许的。在例5.19中,若是将其嵌套查询中的谓词IN改成任意一个比较运算符,都会产生错误。缘由是,该嵌套查询中的子查询返回的不是单字段值,而是两个字段值。
【例5.20】 查询全部平均成绩比“蒙恬”低的学生,并列出这些学生的学号、姓名、专业和平均成绩。
这个查询的关键是首先要找出“蒙恬”的平均成绩,而后才能据此找出其余有关学生的信息。因为“蒙恬”的平均成绩是惟一的,因此咱们能够构造以下的子查询:
SELECT s_avgrade FROM student WHERE s_name = '蒙恬';
该查询返回的结果是78.8。而后由此构造父查询:
SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_avgrade < 78.8
把中间结果78.8去掉之后,将以上两个查询合起来,获得下列的嵌套查询:
SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_avgrade < ( SELECT s_avgrade FROM student WHERE s_name = '蒙恬')
上述嵌套查询后结果以下:
学号 姓名专业 平均成绩
----------------------------------------------------------------------------------------
20170204岳志强 智能科学与技术75.8
20170205贾簿 计算机软件与理论 43.0
20170206李思思 计算机应用技术67.3
20170208张宇 大数据技术 59.3
在SQL Server 2014中,子查询在比较运算符以后或者以前都可有可无,只要查询条件返回的真值同样,则查询结果都相同。例如,下列的嵌套查询与上面的嵌套查询是等价的,查询结果都同样:
SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE ( SELECT s_avgrade FROM student WHERE s_name = '蒙恬') > s_avgrade;
在使用谓词EXISTS的嵌套查询中,只要子查询返回非空的结果,则父查询的WHERE子句将返回逻辑真,不然返回逻辑假。至于返回的结果是什么类型的数据,对这种嵌套查询是可有可无,因此在父查询的目标字段表达式都用符号*,即便给出字段名也无实际意义。
带EXISTS的嵌套查询与前面介绍的嵌套查询的最大区别在于,它们执行的方式不同。带EXISTS的嵌套查询是先执行外层,后执行内层,再回到外层。具体讲,对于每一条记录,父查询先从表中“抽取”出来,而后“放到”子查询中并执行一次子查询;若是该子查询返回非空值(致使WHERE子句返回逻辑真),则父查询将该记录添加到结果集中,直到全部的记录都被进行这样的处理为止。显然,父查询做用的表中有多少条记录,则子查询被执行多少次。在这种查询中,子查询依赖于父查询,因此这类查询又称为相关子查询。
前面介绍的嵌套查询中,先执行子查询,后执行父查询。子查询与父查询无关,因此这类查询称为不相关子查询。
【例5.21】 查询全部选修了《算法设计与分析》的学生学号、姓名和专业。
学生选修课程的信息放在表SC中,而学生的学号、姓名和专业信息则放在表student中,因此该查询要涉及到两个表。显然,该查询能够用不少种方法来实现,下面咱们考虑运用带EXISTS的嵌套查询来完成。相应的SELECT语句以下:
SELECT s_no 学号, s_name 姓名, s_speciality 专业 FROM student WHERE EXISTS( SELECT * FROM SC WHERE student.s_no = s_no AND c_name = '算法设计与分析');
在执行该嵌套查询时,父查询先取表student中的第1条记录,记为r1;而后执行一次子查询,这时发现表SC中存在s_no字段值与r1的s_no字段值相等的记录(记为r2),并且r2在c_name字段上的取值为“算法设计与分析”,因此子查询返回记录r2(非空);因为第1条记录(r1)使得子查询返回值为非空,因此父查询的WHERE子句返回逻辑真,这样父查询便将第1条记录添加到结果集中;重复上述过程,直到表student中全部的记录都被处理完为止。
本查询也能够用带谓词IN的嵌套查询来实现,其查询实现思想也比较直观。首先用子查询返回表SC中全部选修了《算法设计与分析》的学生学号的集合,而后用父查询找出表student中学号在该集合中的学生。相应的查询语句以下:
SELECT s_no 学号, s_name 姓名, s_speciality 专业 FROM student WHERE s_no IN ( SELECT s_no FROM SC WHERE c_name = '算法设计与分析');
SELECT语句返回的结果是若干个记录的集合。集合有其固有的一些运算,如并、交、差等。从集合运算的角度看,能够将每个SELECT语句看成是一个集合。因而,能够对任意两个SELECT语句进行集合运算。在SQL语言,提供了并(UNION)、交(INTERSECT)和差(EXCEPT)等几个集合运算。
两个查询的并(UNION)是指将两个查询的返回结果集合并到一块儿,同时去掉重复的记录。并运算的前提是,两个查询返回的结果集在结构上要一致,即结果集的字段个数要相等以及字段的类型要分别相同。
【例5.22】 查询专业为大数据技术或者平均成绩在良好以上(>=80)的学生,并列出他们的学号、姓名、专业和平均成绩。
这个查询能够看做是如下两个查询并:
-- 查询专业为大数据技术的学生
SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_speciality = '大数据技术';
-- 查询平均成绩在良好以上的学生
SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_avgrade >= 80;
以上这两个查询语句执行后所得的结果分别以下:
学号姓名 专业 平均成绩
-------------------------------------------------------------------------------
20170207 蒙恬 大数据技术 78.8
20170208 张宇 大数据技术 59.3
学号姓名专业 平均成绩
-------------------------------------------------------------------------------
20170201 刘洋 计算机应用技术 98.5
20170202 王晓珂 计算机软件与理论 88.1
20170203 王伟志 智能科学与技术 89.8
将以上两个SELECT语句用关键字UNION连起来就实现了两个查询的并:
(SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_speciality = '大数据技术') UNION (SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_avgrade >= 80);
以上语句执行后获得以下结果:
学号 姓名 专业 平均成绩
--------------------------------------------------------------------
20170201 刘洋 计算机应用技术 98.5
20170202 王晓珂 计算机软件与理论 88.1
20170203 王伟志 智能科学与技术 89.8
20170207 蒙恬 大数据技术 78.8
20170208 张宇 大数据技术 59.3
这个结果正好是上述两个查询结果集的并。
【例5.23】 查询专业为智能科学与技术并且平均成绩在良好以上(>=80)的学生,并列出他们的学号、姓名、专业和平均成绩。
该查询能够看做是专业为智能科学与技术的学生集合和平均成绩在良好以上的学生集合的交集。
基于交运算的SQL语句以下:
(SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_speciality = '智能科学与技术') INTERSECT (SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_avgrade >= 80);
此SQL语句运行结果以下:
学号 姓名 专业 平均成绩
------------------------------------------------------------------------------
20170203 王伟志 智能科学与技术 89.8
【例5.24】 查询专业为智能科学与技术并且平均成绩在良好如下(<80)的学生,并列出他们的学号、姓名、专业和平均成绩。
该查询能够看做是专业为智能科学与技术的学生集合与平均成绩在良好以上的学生集合的差集。
基于差运算的SQL语句以下:
(SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_speciality = '智能科学与技术') EXCEPT (SELECT s_no 学号, s_name 姓名, s_speciality 专业, s_avgrade 平均成绩 FROM student WHERE s_avgrade >= 80);
此SQL语句运行结果以下:
学号姓名 专业 平均成绩
-------------------------------------------------------------------------
20170204岳志强 智能科学与技术75.8