本文总结自《SQL基础教程》
一、视图
(1)通常,我们在创建表时,会通过 INSERT 语句将数据保存到数据库之中,而数据库中的数据实际上会被保存到计算机的存储设备中。因此,我们通过 SELECT 语句查询数据时,实际上就是从存储设备中读取数据,进行各种计算之后,再将结果返回给用户。
使用视图时并不会将数据保存到存储设备之中,而且也不会将数据保存到其他任何地方。实际上视图保存的是 SELECT 语句,从视图中读取数据时,视图会在内部执行该 SELECT 语句并创建出一张临时表。
(2)视图的优点
视图无需保存数据,因此可以节省存储设备的容量。
可以将频繁使用的 SELECT 语句保存成视图,这样就不用每次都重新书写了。
注意:表中存储的是实际数据,而视图中保存的是从表中取出数据所使用的SELECT语句。
(3)创建视图
可以使用 CREATE VIEW 语句创建视图,其基本语法如下图所示:
CREATE VIEW view_name(view_column_1,view_column_2, ……,view_column_n)
AS
<SELECT子句>
注意: SELECT 语句需要书写在 AS 关键字之后。 SELECT 语句中列的排列顺序和视图中列的排列顺序相同,
eg:
以Person1为例:
创建视图的sql语句为:
CREATE VIEW GRADE_MAX(EDUCATION,MAX_GRADE)
AS
SELECT EDUCATION,MAX(GRADE)
FROM Person1
GROUP BY EDUCATION;
此时,视图GRADE_MAX创建完毕。
(4)视图的使用
视图和表一样,可以书写在SELECT 语句的 FROM 子句之中
eg:
SELECT EDUCATION,MAX_GRADE
FROM GRADE_MAX;
在 FROM 子句中使用视图的查询,通常有如下两个步骤:
① 首先执行定义视图的 SELECT 语句
② 根据得到的结果,再执行在 FROM 子句中使用视图的 SELECT 语句
注意: 应该尽量避免在视图的基础上创建视图,因为多重视图会降低 SQL 的性能。
(5)视图的限制
① 定义视图时不能使用ORDER BY子句
这是因为视图和表一样, 数据行都是没有顺序的。
② 对视图进行更新
标准 SQL 中规定:如果定义视图的 SELECT 语句能够满足以下条件,那么这个视图就可以被更新:
SELECT 子句中未使用 DISTINCT
FROM 子句中只有一张表
未使用 GROUP BY 子句
未使用 HAVING 子句
注意:视图和表需要同时进行更新,因此通过汇总得到的视图无法进行更新。
(6)删除视图
可以使用 DROP VIEW 语句来删除视图,其基本语法如下:
DROP VIEW GRADE_MAX(EDUCATION,MAX_GRADE)
二、子查询
(1)子查询的概念
子查询就是一次性视图(SELECT语句)。与视图不同,子查询在SELECT语句执行完毕之后就会消失。
视图并不是用来保存数据的,而是保存读取数据的 SELECT 语句。子查询就是将用来定义视图的SELECT语句直接用于FROM子句当中。
eg:
CREATE VIEW GRADE_MAX(EDUCATION,MAX_GRADE)
AS
SELECT EDUCATION,MAX(GRADE)
FROM Person1
GROUP BY EDUCATION;
SELECT EDUCATION,MAX_GRADE
FROM GRADE_MAX;
能够实现同样功能的子查询的sql代码如下:
SELECT EDUCATION,MAX_GRADE
FROM (SELECT EDUCATION,MAX(GRADE) AS MAX_GRADE
FROM Person1
GROUP BY EDUCATION) AS GRADE_MAX;
该 SELECT 语句包含嵌套的结构,首先会执行 FROM 子句中的 SELECT 语句,然后才会执行外层的 SELECT 语句。
注意:子查询就是将用来定义视图的 SELECT 语句直接用于FROM 子句当中。
(2)子查询的嵌套
虽然子查询的层数原则上没有限制,可以无限嵌套子查询,但是由于随着子查询嵌套层数的增加, SQL 语句会变得越来越难读懂,性能也会越来越差。因此,应尽量避免使用多层嵌套的子查询
(3)子查询的名称
原则上子查询必须设定名称, 为子查询设定名称时需要使用 AS 关键字,该关键字有时也可以省略
(4) 标量子查询
标量子查询就是返回单一值的子查询。标量子查询则有一个特殊的限制,那就是必须而且只能返回 1 行 1列的结果,也就是返回表中某一行的某一列的值。因此标量子查询的返回值可以用在 = 或者 <> 这样需要单一值的比较运算符之中。
eg:
在where子句中使用标量子查询,如果要求出表Person1中GRADE大于等于最大值的记录的ID、NAME、EDUCATION,则代码如下:
SELECT ID,NAME,EDUCATION
FROM Person1
WHERE GRADE>=(SELECT MAX(GRADE)
FROM Person1);
(5) 标量子查询的书写位置
**通常任何可以使用单一值的位置都可以使用标量子查询。**具体来说, 能够使用常数或者列名的地方,无论是 SELECT 子句、 GROUP BY 子句、 HAVING 子句,还是ORDER BY 子句,几乎所有的地方都可以使用。
注意:标量子查询必须返回单一值。
三、 关联子查询
(1)普通子查询和关联子查询的区别
eg:
如果要按照EDUCATION的分类来计算GRADE的平均值,若使用以下sql语句则会报错:
SELECT ID,NAME,EDUCATION
FROM Person1
WHERE GRADE>=(SELECT MAX(GRADE)
FROM Person1
GROUP BY EDUCATION);
报错的原因在于该sql代码会返回多行数据,并不是标量子查询。此时,可以使用关联子查询获得想要的结果:
SELECT ID,NAME,EDUCATION
FROM Person1 AS P1
WHERE GRADE>=(SELECT MAX(GRADE)
FROM Person1 AS P2
WHERE P1.EDUCATION=P2.EDUCATION
GROUP BY EDUCATION);
这里起到关键作用的就是在子查询中添加的 WHERE 子句的条件。 在对表中某一部分记录的集合进行比较时,就可以使用关联子查询。
注意:在细分的组内进行比较时,需要使用关联子查询。
(2) 可使用关联子查询对集合进行切分
(3) 结合条件一定要写在子查询中
如果写在子查询之外,则在关联名称的作用域之外,就会出错。 这是因为子查询内部设定的关联名称,只能在该子查询内部使用