DDL(数据定义)
DROP 子句 用于删除指定的列名,
◼ 若选择RESTRICT ,则删除的基本表不能被其他表的约
束所引用(如 CHECK , FOREIGN KEY 等约束),不
能有视图,不能有触发器,不能有存储过程或函数等。
如果存在这些依赖该表的对象,则此表不能被删除。
◼ 若选择 CASCADE ,则该表的删除没有限制条件。在删
除基本表的同时,相关的依赖对象,例如视图等都将被
一起删除。
◼ 一般在缺省情况下默认为 RESTRICT , 与具体实现有关
DML(数据操作)
一。插入
INSERT INTO < 表名 > [(< 属性列 1>[,< 属性列 2 > ... )]
VALUES (< 常量 1> [ , < 常量 2>] ...
);
◼ INTO 子句
◼ 指定要插入数据的表名及属性列
◼ 属性列的顺序可以与表定义中的顺序不一致
◼ 没有指定属性列 :表示要插入的是一条完整的元组,
且属性列属性与表定义中的顺序一致
◼ 指定部分属性列:插入的元组在其余属性列上取空
值或者是默认值
◼ VALUES 子句
◼ 提供的值必须与 INTO 子句匹配:个数、顺序和值的
类型
【例】在学生表中插入一个学生元组,其学号为
101215 ,姓名为李斌,男, 19 岁,是计算机系
的学生。
INSERT INTO Student
VALUES( ' 101215 ' , ' 李斌' , '男' ,19, '计算机' );
INSERT INTO Student ( Sno, Sname, Sdept, Sage, Ssex )
VALUES( ' 101215 ' , ' 李斌' , '计算机' ,19, '男' );
将子查询结果插入指定表中
INSERT INTO < 表名 >[(< 列名 1>[,< 列名 2>, ])]
<SELECT 语句 >; /* 子查询 */ ;
◼ INTO 子句
◼ 指定要插入数据的表名及属性列
◼ 属性列的顺序可与表定义中的顺序不一致
◼ 没有指定属性列,则表示插入一条完整的元组
◼ 指定部分属性列,则在其余属性列上取空值
◼ 子查询
◼ SELECT 子句目标列必须与 INTO 子句匹配:个数、
顺序和值的类型
【例】计算计算机系每个学生的平均成绩,并保存
在 CS-AVG 表中。
1. 生成学生的平均成绩表CS-AVG
2. 在CS-AVG中插入计算机系学生的平均成绩
CREATE TABLE CS-AVG
( Sno CHAR(6)NOT NULL ,
Grade NUMBER(4,1));
INSERT INTO CS-AVG (Sno, Grade)
SELECT Sno, AVG(Grade) FROM SC
WHERE Sno IN (
SELECT Sno FROM Student
WHERE Sdept='CS')
GROUP BY Sno ;
二。更新与删除
DQL(数据查询)
一。注意DISTINCT短语的作用范围是所有目标列
错误的写法
SELECT DISTINCT Cno , DISTINCT Grade
FROM SC;
正确的写法
SELECT DISTINCT Cno , Grade
FROM SC;
二。空值查询:"IS NULL"不能用 "= NULL**"**代替
三。使用GROUP BY子句分组查询
◼ 细化聚集函数的作用对象
◼ 未对查询结果分组,聚集函数将作用于整个查询结果
◼ 对查询结果分组后,聚集函数将分别作用于每个组
◼ 分组方法
◼ 按指定的一列或多列值分组, 值相等的为一组
◼ 使用 GROUP BY 子句后, SELECT 子句的列名列
表中只能出现分组属性和聚集函数
◼ GROUP BY 子句的作用对象是查询的中间结果表
【例】求各个课程号及相应的选课人数。
SELECT Cno , COUNT(*) -- COUNT(Sno)
FROM SC
GROUP BY Cno ;
【例】查询选修了 3 门以上课程的学生学号
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*) >3 ;
查询有 3 门以上课程是 90 分以上的学生的学
号及( 90 分以上的)课程数
SELECT Sno, COUNT(*)
FROM SC
WHERE Grade>=90
GROUP BY Sno
HAVING COUNT(*)>=3;
四。where与having的区别
WHERE
子句允许你指定过滤条件,这些条件基于表中的单个行。你不能在WHERE
子句中使用聚合函数(如SUM()
,AVG()
,COUNT()
, 等)来过滤分组。GROUP BY
子句通常与聚合函数一起使用,以计算每个组的汇总值。你不能在GROUP BY
子句中指定单个行的条件,但可以在HAVING
子句中这样做,HAVING
子句允许你基于聚合函数的结果来过滤分组。
五。连接查询
连接条件中各 连接字段 的类型必须是 可比的 ,但不必是
相同的
六。嵌套查询(又称子查询)
子查询的限制
◼ 不能使用 ORDER BY 子句
嵌套查询的分类与求解方法
◼ 不相关子查询
◼ 子查询的查询条件不依赖于父查询
◼ 由里向外逐层处理。每个子查询在上一级查询处理之前
求解,子查询的结果用于建立其父查询的查找条件。
◼ 相关子查询
◼ 子查询的查询条件依赖于父查询
◼ 先取外层查询中表的第一个元组,根据它与内层查询相
关的属性值处理内层查询,若 WHERE 子句返回值为真,
则取此元组放入结果表;然后再取外层表的下一个元组;
重复这一过程,直至外层表全部检查完为止
【例】找出每个学生所选修课程成绩超过该门课
程平均成绩的课程号。
SELECT Sno, Cno /* 外层查询 / 父查询 */
FROM SC x
WHERE Grade >=(SELECT AVG(Grade)
FROM SC y
WHERE y.Cno=x.Cno);
/* 内层查询 / 子查询 */
子查询不能在比较符之前
◼ 错误 的例子
SELECT Sno, Sname, Sdept
FROM Student
WHERE ( SELECT Sdept
FROM Student
WHERE Sname= ' 刘晨 ' )
= Sdept ;
带有 ANY 或 ALL 谓词的子查询
> ANY
大于子查询结果中的某个值
> ALL
大于子查询结果中的所有值
= ANY
等于子查询结果中的某个值
=ALL
等于子查询结果中的所有值(通常没有实际意义)
!= (或 <> ) ANY 不等于子查询结果中的某个值
!= (或 <> ) ALL
不等于子查询结果中的任何一个值
ANY 和 ALL 谓词有时可以用聚集函数来实现
◼ 用聚集函数实现子查询通常比直接用 ANY 或 ALL 查询效
率要高,因为前者通常能够减少比较次数。
【例】查询其他系中比 CS 系 任意一个 学生年龄小的
学生姓名和年龄
◼ 用 ANY 谓词实现
SELECT Sname, Sage
FROM Student
WHERE Sage < ANY (
SELECT Sage
FROM Student
WHERE Sdept= 'CS')
AND Sdept <> 'CS' ;
◼ 用聚集函数实现
SELECT Sname, Sage
FROM Student
WHERE Sage < (
SELECT MAX(Sage)
FROM Student
WHERE Sdept= 'CS')
AND Sdept <> 'CS' ;
带有 EXISTS 谓词的子查询
◼ 带有 EXISTS 谓词的子查询不返回任何数据,只产生逻
辑真值" true "或逻辑假值" false "。
◼ 若内层查询结果 非空 ,则返回 真值
◼ 若内层查询结果为空,则返回假值
◼ 由 EXISTS 引出的子查询,其目标列表达式通常用 * , 因
为带 EXISTS 的子查询只返回真值或假值,给出列名无
实际意义
【例】查询所有选修了1号课程的学生姓名。
◼ 思路分析:在 Student 中依次取每个元组的 Sno值,用此
值去检查 SC 关系;若 SC 中存在这样的元组,其 Sno 值
等于此 Student.Sno 值,且Cno= ' 1 ' ,则取此
Student.Sname 送入结果关系
用嵌套查询
SELECT Sname
FROM Student
WHERE EXISTS
(SELECT *
FROM SC
WHERE Sno=Student.Sno
AND Cno= ' 1 ') ;
◼ 所有 带 IN 谓词、比较运算符、 ANY 和 ALL 谓词的子查询
都能用带 EXISTS 谓词的子查询等价替换。
◼ 带有 EXISTS 谓词的相关子查询只关心内层查询是否有
返回值,不需要查具体值,效率不低于相关子查询。
用 EXISTS/NOT EXISTS 实现全称量词
◼ SQL 语言中没有全称量词 任取 ( For all )
◼ 可以把带有全称量词的谓词转换为等价的带有存在量词
的谓词:
(任取 x)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)) ;
用 EXISTS/NOT EXISTS 实现逻辑蕴函
◼ SQL 语言中没有蕴函 (Implication) 逻辑运算
【例】查询至少选修了学生95001选修的全部课程的
学生的学号
解题思路:
◼ 用逻辑蕴函表达:查询学号为x的学生,对所有的课程y,
只要95001学生选修了课程y,则x也选修了y
◼ 变换后语义: 对于学生 x ,不存在这样的课程 y ,学生
95001选修了 y ,而学生 x 没有选 。
SELECT DISTINCT Sno
FROM SC SCX
WHERE NOT EXISTS
(SELECT *
FROM SC SCY
WHERE SCY.Sno = '95001'
AND NOT EXISTS
(SELECT *
FROM SC SCZ
WHERE SCZ .Sno= SCX. Sno AND
SCZ .Cno= SCY .Cno)) ;#一个表涉及多次查询时最好起别名,而且as是可以省略的
七。集合查询
并操作
◼ 语法形式
< 查询块 >
UNION [ALL]
< 查询块 >;
◼ 两个查询结果的属性列个数相同,对应项的数据
类型必须能够通过隐式转换相互兼容。
◼ 使用 UNION 合并多个结果集时,系统会 自动去掉
重复元组 。
◼ 使用 UNION ALL 操作符,可以保留重复元组
UNION 结果集中的列名与 UNION 运算中第一个
SELECT 语句的结果集中的列名相同,
其他的 SELECT 语句的结果集列名将被忽略。
差操作
◼ 标准 SQL 中没有提供集合差操作,但可用其他方
法间接实现。
【例】查询学生姓名与教师姓名的差集。 实际上是
查询学校中未与教师同名的学生姓名 。
SELECT DISTINCT Sname
FROM Student
WHERE Sname NOT IN
(SELECT Tname
FROM Teacher);
#另一种方式
SELECT Sname
FROM Student
EXCEPT
SELECT Tname
FROM Teacher;
对集合操作结果的排序
◼ 在执行集合操作时,默认按照最后结果表中第一
列数据的升序方式排列记录。
◼ 各 SELECT 子句不能含有 ORDER BY 子句,但是可
以将 ORDER BY 子句放在最后的 SELECT 语句后面,
以便对最后的结果表排序。
◼ ORDER BY 子句只能用于对最终查询结果排序,
不能对中间结果排序。
◼ 任何情况下, ORDER BY 子句只能出现在最后。
◼ 对集合操作结果排序时, ORDER BY 子句中最好
用数字指定排序的列属性,以免出错
错误写法
SELECT *
FROM Student
WHERE Sdept= 'CS'
ORDER BY Sno
UNION
SELECT *
FROM Student
WHERE Sage<=19
ORDER BY Sno ;
正确写法
SELECT *
FROM Student
WHERE Sdept= 'CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19
ORDER BY 1 ;
基于派生表的查询
◼ 子查询出现在 FROM 子句中,这时子查询生成的
临时派生表( Derived Table )成为主查询的查询
对象
【例】找出每个学生超过他自己选修课程平均成绩
的课程号。
SELECT Sno, Cno
FROM SC, ( SELECT Sno, Avg(Grade) avg_grade
FROM SC
GROUP BY Sno ) AS Avg_sc
WHERE SC.Sno = Avg_sc.Sno
and SC.Grade >=Avg_sc.avg_grade;
约束
索引
◼ 在一个基本表上最多只能建立一个聚集索引
◼ 聚集索引可以包含多个列(组合索引)
◼ 聚集索引的适用范围
◼ 很少对基表进行增删操作
◼ 很少对其中的变长列进行修改操作