数据库基础

数据查询
数据查询是数据库的核心操作,该篇将着重介绍数据查询的五种方式:单表查询、连接查询、嵌套查询、集合查询和基于派生表的查询。

基本语法
一般格式(尖括号“<>”表示必填,“[]”表示可选,“|”用于区别不同选择):

SELECT [ ALL | DISTINCT ] <目标列表达式> [,<其余目标列表达式>]

FROM <表名或视图名> [,<其余表名或视图名>]

[ WHERE <条件表达式> ]

[ GROUP BY <列名> [ HAVING <条件表达式> ] ]

[ ORDER BY <列名> [ ASC | DESC ] ] ;

(1)整个SELECT语句的含义是,根据WHERE子句的条件表达式,从FROM子句指定的范围(基本表、视图或派生表)中找出满足条件的元组,再按SELECT子句中的目标列表达式选出元组中的属性值形成结果表。

(2)形成的结果表可能会含有重复行,若SELECT子句中指定ALL关键词,则保留结果表中的所有重复行。反之,若指定DISTINCT关键词,则去掉重复行。默认为ALL。

(3)GROUP BY子句用于对查询结果(执行SELECT-FROM语句后的结果)按属性值(同一列或几列相应的值)相等的规则进行分组,随后可用HAVING子句对划分好的组依组处理。

(4)ORDER BY子句用于对查询结果根据某一列或几列的属性值,按升序(ASC)或降序(DESC)排列。

可能看完上面这一坨拗口(虽然我已经很努力在概括了)的句子后,大家还是云里雾里的。不用担心,后面会继续作介绍。

单表查询
单表查询是指仅涉及一个表的查询。

  1. 选择表中的若干列
    SELECT-FROM语句对应关系代数的“投影”(我是链接)

(1)指定查询

如查询全体学生的学号与名字:

SELECT Sno,Sname

FROM Student;

(2)全部查询

如查询全体学生的详细信息(学号,姓名,性别,年龄,院系):

SELECT Sno,Sname,Ssex,Sage,Sdept

FROM Student;

SQL提供了用于全选语法糖,如果你允许结果表中属性列的排列顺序与原表相同,则上面的语句等价于

SELECT *

FROM Student;

(3)表达式查询

如查询学生姓名、出生年份(假设今年是2018年)和所在院系,并且所在院系用小写字母表示:

SELECT Sname, ‘Year of Birth:’, 2018-Sage BIRTHDAY, LOWER(Sdept) DEPARTMENT

FROM Student;

分析:

‘Year of Birth:’ —— 字符串常量直接输出

2018-Sage BIRTHDAY —— 算术表达式求出生年份,并且该列属性名取别名为“BIRTHDAY”

LOWER(Sdept) DEPARTMENT —— 使用SQL函数LOWER()实现字母转换成小写的功能,并取别名为“DEPARTMENT”

  1. 选择表中的若干元组
    (1)对重复行的处理判断

SQL语句先处理列,再处理行。两个本来不完全相同的元组,在投影到某些列后,可能会出现重复行,若指定DISTINCT关键词,重复行会被消除,若指定ALL关键词,则重复行被保留,系统默认为ALL。

(2)查询满足条件的元组

SELECT-FROM-WHERE语句对应关系代数的“选择”。

常用查询条件
查询条件 谓词
比较 [NOT]比较运算符
确定范围(包括端点) [NOT] BETWEEN AND
确定集合 [NOT] IN
字符匹配 [NOT] LIKE
空值 IS NULL,IS NOT NULL
多重条件 AND,OR,NOT
//查询年龄在20~23岁之间(包括20和23岁)的学生的姓名:

SELECT Sname

FROM Student

WHERE Sage BETWEEN 20 AND 23;

//查询计算机科学(CS)、数学系(MA)的学生姓名:

SELECT Sname

FROM Student

WHERE Sdept IN (‘CS’,‘MA’);

//查询无成绩的学生的姓名和学号:

SELECT Sname,Sno

FROM Student

WHERE Grade IS NULL;

(3)字符匹配

在字符匹配中,“LIKE”等价于“=”。

此外,在字符匹配中涉及到两个通配符(%和_)和换码字符短语(ESCAPE ‘’)

%代表任意长度的字符串,例如a%b,表示以a为开头,b为结尾的字符串;

_代表任意单个字符;

ESCAPE ''表示“\”后紧跟的字符“%”或“_”不作为通配符使用。

//查询所有姓刘的学生的姓名和学号:

SELECT Sname,Sno

FROM Student

WHERE Sname LIKE ‘刘%’;

//查询姓“欧阳”且名字只有三个字的学生的姓名和学号:

SELECT Sname,Sno

FROM Student

WHERE Sname LIKE ‘欧阳_’

//查询DB_Design课程的课程号和学分:

SELECT Cno,Ccredit

FROM Student

WHERE Cname LIKE ‘DB_Design’ ESCAPE ‘’;

  1. ORDER BY子句
    //查询选修了3号课程的学生的学号及其成绩,查询结果按分数的降序排序:

SELECT Sno,Grade

FROM SC

WHERE Cno = ‘3’

ORDER BY Grade DESC;

需要留意的是,对于空值,排序时显示的顺序由具体系统来决定。

  1. 聚集函数
    常用聚集函数
    COUNT(*) 统计元组个数
    COUNT( [ DISTINCT | ALL ] ) 统计一列中值的个数
    SUM( [ DISTINCT | ALL ] ) 计算一列值的总和
    AVG( [ DISTINCT | ALL ] ) 计算一列值的平均值
    MAX( [ DISTINCT | ALL ] ) 求一列值中的最大值
    MIN( [ DISTINCT | ALL ] ) 求一列值中的最小值
    注意点:

(1)指定DISTINCT关键词,表示计算时要忽略重复值。如果不指定DISTINCT,则默认为ALL关键词,将重复值计算在内。

(2)WHERE子句不能用聚集函数作为条件表达式,聚集函数只能在SELECT子句和HAVING子句中使用。WHERE子句与HAVING子句的区别在于作用对象不同。WHERE子句作用于基本表或视图,从中选择满足条件的元组,而HAVING子句作用于分组,从中选择满足条件的组。

(3)除COUNT(*)外,其他聚集函数遇到空值后都会自动跳过。

//查询学生总人数:

SELECT COUNT(*)

FROM Student;

//查询选修了课程的学生人数:

SELECT COUNT(DISTINCT Sno)

FROM SC;

//计算选修1号课程的学生平均分:

SELECT AVG(Grade)

FROM SC

WHERE Cno = ‘1’;

  1. GROUP BY子句
    (1)GROUP BY子句将查询结果按一列或多列的属性值分组,组相等的行归为一组。若不对查询结果进行分组,聚集函数将作用于整个查询结果。分组后,聚集函数会作用于每个小组并返回一个函数值。

//求各课程号及相应的选课人数:

SELECT Cno,COUNT(Sno) /分组后,COUNT函数会对每个组都进行计算/

FROM SC

GROUP BY Cno; /对查询结果按Cno的值分组/

(2)GROUP BY子句还可以配合上HAVING短语(回顾上面的注意点2)指定筛选条件。

//查询选修了三门以上课程的学生学号和选修的课程数量:

SELECT Sno

FROM SC

GROUP BY Sno /对查询结果按Sno的值分组/

HAVING COUNT(*) > 3; /分组后 * 会依次表示不同的组,COUNT函数再计算每个组的元组数/

连接查询
连接查询是指同时涉及两个以上的表的查询。

  1. 等值与非等值连接查询
    连接查询中的WHERE子句是由连接条件和选择条件组成的复合条件。执行复合条件的连接查询时是先执行选择条件,再执行连接条件,这是一种高效执行过程。

连接条件是指用比较运算符连接两个表中的某个属性列,连接条件中的列名称为连接字段,字段的类型必须是可比的,但名字不必相同。如果属性列名称不同,可以省略表名前缀。

当连接条件中的比较运算符为“=”时,连接称为等值连接,否则称为非等值连接。

有时等值连接后会出现重复列,将重复列取消的连接称为自然连接。(可回顾“专门的关系运算”)

//查询每个学生及其选修课程的情况:

<等值连接>

SELECT Student.,SC. /*Student.*和SC.表示两表中的所有属性列,所以表中会出现重复列/

FROM Student,SC

WHERE Student.Sno = SC.Sno;

<自然连接>

SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade /虽然表中不会出现重复列,但是代码变长了_(:з」∠)_/

FROM Student,SC

WHERE Student.Sno = SC.Sno;

//查询选修2号课程,且成绩在90分以上的所有学生姓名和学号:

<与选择条件复合>

SELECT Student.Sno,Sname

FROM Student,SC

WHERE Student.Sno = SC.Sno /连接条件/

           AND Cno = '2'                             /*选择条件*/

           AND Grade >= 90;
  1. 自身连接
    连接操作不仅可以在不同表上进行,还可以是表与自身的连接。

为了实现自身连接,同时保证逻辑的正确性,我们需要给表起若干个别名。

//查询每一门选修课(Cno)的先修课程(Cpno):

<思路>选修课和先修课同位于表Course,我们需要起两个别名,分别表示选修课和先修课所在的表。

SELECT FIRST.Cno,SECOND.Cpno /FIRST表是选修课所在表,SECOND表是先修课所在表/

FROM Course FIRST,Course SECOND /给Course起两个别名/

WHERE FIRST.Cpno = SECOND.Cno; /在FIRST表中找先修课,再在SECOND表中找课程号/

  1. 外连接
    采用外连接可以使被舍弃的悬浮元组显示在查询结果中。(可回顾“专门的关系运算”)

//查询每个学生及其选修课的情况

SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade

FROM Student LEFT OUTER JOIN SC USING(Sno); /USING(Sno)等价于Student.Sno = SC.Sno/

细心的同学可以注意到,外连接里我们没有用到WHERE子句来连接两个表,这是因为例子中使用了JOIN短语。在FROM子句中使用JOIN就可以实现连接,而且

FROM Student INNER JOIN SC ON Student.Sno = SC.Sno; 等价于 WHERE Student.Sno = SC.Sno;

NATURAL JOIN 表示自然连接

LEFT OUTER JOIN 表示左外连接(同理可推导右外连接)

连接查询时使用WHERE还是JOIN就根据大家的编程习惯而定喽。

  1. 多表连接
    //查询每个学生的姓名、选修课程及成绩:

SELECT Sname,Cno,Grade

FROM Student,Course,SC

WHERE Student.Sno = SC.Sno AND Course.Cno = SC.Cno;

嵌套查询
在SQL语言中,我们司空见惯的SELECT-FROM-WHERE语句被称为一个查询块。将一个查询块嵌套在另一个查询块的WHERE子句或HAVING短语中的查询,我们定义为嵌套查询。

嵌套查询使用户可以用多个简单的查询构成复杂的查询,增强SQL的查询能力,这种查询正是SQL(结构化查询语言)中“结构化”的含义所在。

1.带有IN谓词的子查询
在嵌套查询中,子查询的结果往往是一个集合,IN正是我们之前提到的“确定集合”的查询谓词。

//查询选修了课程名为“信息系统”的学生学号和名字:

<嵌套查询>

SELECT Sno,Sname

FROM Student

WHERE Sno IN /得到学生学号/

         (SELECT Sno

           FROM SC                          /*用SC表将Student表和Course表联系起来

           WHERE Cno IN                 /*得到课程号*/

                        (SELECT Cno

                          FROM Course

                          WHERE Cname = '信息系统'

                         )

          );

<连接查询>

*有些嵌套查询可以用连接替代,有些却不可以。但在实际应用中,能够用连接查询的尽量用连接查询!

SELECT Student.Sno,Sname

FROM Student,Course,SC

WHERE Student.Sno = SC.Sno

         AND SC.Cno = Course.Cno

         AND Course.Cname = '信息系统';

*在上面的嵌套查询中,子查询的查询条件不依赖于父查询,子查询的查询结果用于建立父查询的查询条件,这样的查询叫做不相关子查询。下面要介绍的嵌套查询都属于相关子查询,即子查询的查询条件依赖于父查询。求解相关子查询不能像求解不相关子查询那样一次将子查询解出来,然后求解父查询。由于子查询的查询条件与父查询相关,所以需要反复求值。

  1. 带有比较运算符的子查询
    这种查询用比较运算符来连接父查询和子查询,即用比较运算符取代IN短语。

//找出每个学生超过自己选修课平均成绩的课程号:

SELECT Sno,Cno

FROM SC x /给SC起两个别名/

WHERE Grade >=

         (SELECT AVG(Grade)

           FROM SC y

           WHERE x.Sno = y.Sno

         );
  1. 带有ANY(SOME)或ALL谓词的子查询
    子查询返回单值时可以用比较运算符,但返回多值时要加上ANY(有的系统用SOME)或ALL谓词修饰符。

短语 语义

ANY
大于最小值

<ANY 小于最大值

ALL 大于最大值
<ALL 小于最小值
//查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄:

/要注意,这里的“任意一个”并不是我们日常理解的“所有”。前面说过相关子查询的嵌套查询时反复求值的,因此这里的“任意一个”是指每一次求值时的“所有”,题干要表达“所有”的时候一般会说“全部”。但其实用词也没那么死板…具体问题具体分析吧。/

<使用ANY谓词>

SELECT Sname,Sage

FROM Student

WHERE Sage <ANY

         (SELECT Sage

           FROM Student

           WHERE Sdept = 'CS')

AND Sdept != ‘CS’; /不等于也可以用<>,其实从敲键盘的角度来说,<>还舒服一点/

                                                /*而且要注意,最后一行AND语句是父查询的选择条件之一*/

<使用聚集函数>

*在实际应用中,用聚集函数的查询效率更高!

SELECT Sname,Sage

FROM Student

WHERE Sage <

         (SELECT MAX(Sage)

           FROM Student

           WHERE Sdept = 'CS')

and stept !='cs’

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值