数据库课程梳理——SElECT

SELECT语句详细分析

单表查询

SELECT * / 列名 / 聚集函数(列名)/ 算术表达式 / ‘字符串常量’ /

这里的*号代表全部。


统计函数(聚集函数)

聚集函数只能用于SELECT子句和GROUP BY中的HAVING子句,而不能用于WHERE子句。

函数 说明
AVG() 指定列的平均值
COUNT() 指定列的统计行数
MAX() 指定列的最大值
MIN() 指定列的最小值
SUM() 指定列的和

WHERE子句

SELECT *
FROM Student
WHERE 
查询条件 谓词
确定范围 BETWEEN AND, NOT BETWEEN AND
确定集合 IN,NOT IN
字符匹配 LIKE ,NOT LIKE
空值 IS NULL, IS NOT NULL

在SQL中模糊查询的方式主要有两种,一种是通配符,另一种是正则表达式。它们的不同很简单,通配符是可以一对多,而正则表达式这是一一对应,理解为一种“格式”。具体可以参考这篇一文理解通配符和正则表达式

正常情况使用=<>来判断。有通配符时,使用LIKE关键字。

ORDER/GROUP BY子句

  • ORDER BY子句
SELECT Sno,Grade
FROM Sc
WHERE Cno='2'
ORDER BY Grade[ASC|DESC];
  • GROUP BY

我们知道聚集函数或者函数表达式是针对某一列进行,而GROUP BY是为了细化聚集函数的作用对象,将列分组,然后作用于每一组。

求每个课程号即相应的选课人数

SELECT Cno,COUNT(Sno)
FROM SC
GROUP BY Cno;

HAVING子句

HAVING在分组的基础上作进一步的筛选

选课门大于2的学生学号

SELECT Sno,COUNT(Cno)
FROM Student
GROUP BY Sno
HAVING COUNT(*)>2;

平均成绩大于90的学号

SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno
HAVING AVG(Grade)>90;

WHEREGROUP BY之前操作,HAVINGGROUP BY之后进行,WHERE是对元组进行过滤,而HAVING是对分组进行过滤。

女生人数大于10的系

SELECT Sdept,COUNT(*)
FROM Student
WHERE Ssex='女'
GROUP BY Sdept
HAVING COUNT(*)>10;

连接查询

等值连接

SELECT Student.*,SC.*
FROM Student,SC
WHERE Student.Sno=SC.Sno;
SELECT Student.Sno,SC.Sname
FROM Student,SC
WHERE Student.Sno=SC.Sno AND Cno=2 AND Grade >90;

自连接

  • 需要给表起别名以区别
  • 因为有同名属性,因此必须使用表名前缀

比如查询先修课的先修课,使用自连接。

表名和属性名的别名都是使用关键字AS

SELECT First.Cno,Second.Cpno
FROM Course AS First,Course AS Second
WHERE First.Cpno=Second.Cno

外连接

有悬浮元组。缺失属性补NULL。

多表连接

由二到多的一个推广。

嵌套查询

查询块:一个SELECT-FROM-WHERE语句。

嵌套查询也称子查询,说白了就是查询套查询。

=只是单值判断,而子查询的返回值未必是一个,IN是范围,因此IN更合理

分类

  • 子查询是独立进行,不相关子查询

    一般是可以用连接替代的

  • 子查询依赖父查询的,送条件

    因为子查询不只是一个结果,而是两方有关联。这是一般的连接是不能替代的。

    SELECT Sno,Cno
    FROM SC AS x
    WHERE Grade >=(SELECT AVG(Grade)
                  FROM SC y
                  WHERE y.Sno=x.Sno)
    

ANYALL的用法

ANY是其中一个,ALL是所有

完全可以通过聚集函数MAX() MIN()替代

EXISTS

返回真值

相关子查询

SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno AND Cno='1');

NOT EXISTS

SELECT Sname
FROM Student
WHERE NOT EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno AND Cno='1');

通过EXISTS实现全称量词

∀ P = ¬ ( ∃ x ( ¬ P ) ) {\forall}P={\lnot}({\exists}x(\lnot P)) P=¬(x(¬P))

查询选修了所有课程的学生姓名

SELECT Sname
FROM Student
WHERE NOT EXISTS
	(SELECT *
    FROM Course
    WHERE NOT EXISTS
    	(SELECT *
        FROM SC
        WHERE Sno=Student.Sno
        	AND Cno=Course.Cno));

理解这个SQL语句,第一,每一次SELECT返回的都是一个集合,这个集合可能只有一个元素,也可能是空集NULL。非空集对应真值1,即存在EXISTS,而空集NULL对应真值0,即不存在。

那我们可以这样分析,先看最里面,给定一个学生,判断所有课程,相当于一个连接判断是否存在,如果满足条件,则不返回该门课程,所有课程都满足都不返回,返回一个空集NULL即0,再结果一次求反,返回1,输出学生姓名。一旦有一门不满足条件,说明最里面返回的不是空集即1,再一次求反,返回0,不输出学生姓名。

通过EXISTS实现逻辑蕴含

查询至少选修了学生201215122选修的全部课程的学生号码

∀ ( y ) p → q = ¬ ( ∃ y ( ¬ ( ¬ p ∨ q ) ) ) = ¬ ∃ y ( p ∧ ¬ q ) {\forall}(y)p {\rightarrow}q={\lnot}({\exists}y({\lnot({\lnot}p{\lor}q)}))={\lnot}{\exists}y(p{\land}\lnot q) (y)pq=¬(y(¬(¬pq)))=¬y(p¬q)

把父查询的信息,一层层送进去

SELECT DISTINCT Sname
FROM SC AS SCX
WHERE NOT EXISTS(
	SELECT *
	FROM SC AS SCY
	WHERE SCY.Sno='201215122'
    	AND NOT EXISTS
    	(SELECT *		#EXISTS后要跟一个完整的查询块,返回真值,这里只是指定从哪个表找,并无实际返回
    	FROM SC AS SCZ	#意义,返回什么都无所谓,所以用*。FROM 表只是中间作用
    	WHERE SCZ.Sno = SCX.Sno AND
			SCZ.Cno=SCY.Cno
    	)
)

集合查询

集合操作

每次SELECT返回的结果其实就是元组的集合。因此下列集合操作可以用在各个select语句之间。但是要注意格式要相同,元组列数和数据类型。

UNION(DISTINCT OR),交INTERSECT,差操作EXCEPT

基于派生表的查询

子查询出现再FROM子句中的,子查询生成临时表作为主查询的查询对象。

猜你喜欢

转载自blog.csdn.net/qq_45175218/article/details/104874522
今日推荐