定义:是一种数据结构,用于加快数据的检索速度。它类似于一本书的目录,通过记录表中的值以及各值的存储位置,帮助数据库程序快速找到表中的数据,而不必扫描整个表。
作用:能显著提升数据查询性能,减少查询时的磁盘 I/O 操作。例如在一个有大量记录的Students
表中,若要查找特定学号的学生信息,有索引时可快速定位,无索引则可能需全表扫描。
分类:
利弊:
索引创建
CREATE CLUSTER INDEX Stusname ON Student(Sname);
CREATE CLUSTERED INDEX Stusname ON Student(Sname);
Student
表按学号升序建唯一索引:CREATE UNIQUE INDEX Stusno ON Student(Sno);
Course
表按课程号升序建唯一索引:CREATE UNIQUE INDEX Coucno ON Course(Cno);
SC
表按学号升序和课程号降序建唯一索引:CREATE UNIQUE INDEX SCno ON SC(Sno ASC, Cno DESC);
索引删除
DROP INDEX <索引名>;
,如删除Student
表的Stusname
索引:DROP INDEX Stusname;
DROP INDEX Stusname ON Student;
DROP INDEX Student.Stusname;
SELECT
语句,可选择列、指定表或视图、添加条件过滤、分组、排序等操作。例如SELECT Sno, Sname FROM Student WHERE Sdept = 'CS' ORDER BY Sno;
,从Student
表中查询计算机系学生的学号和姓名,并按学号升序排序。-- 查询全体学生的学号和姓名
SELECT Sno,Sname
FROM Student;
-- 查询全体学生的姓名及其出生年份
SELECT Sname,2024-Sage AS BirthYear
FROM Student;
DISTINCT
关键字;根据条件查询使用各种谓词,如比较、范围、集合、字符匹配、空值判断等;对查询结果排序用ORDER BY
子句。例如:-- 查询选修了课程的学生学号,消除重复行
SELECT DISTINCT Sno
FROM SC;
-- 查询年龄在20 - 23之间的学生的姓名、系别和年龄
SELECT Sname,Sdept,Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
-- 查询所有姓刘的学生的姓名、学号和性别
SELECT Sname,Sno,Ssex
FROM Student
WHERE Sname LIKE '刘%';
查询条件 | 谓词 |
---|---|
比 较 | =,>,<,>=,<=,!=,<>,!>,!<; NOT+上述比较符 |
确定范围 | BETWEEN AND,NOT BETWEEN AND |
确定集合 | IN,NOT IN |
字符匹配 | LIKE,NOT LIKE |
空 值 | IS NULL,IS NOT NULL |
多重条件 | AND,OR |
COUNT
、SUM
、AVG
、MAX
、MIN
;分组使用GROUP BY
子句,可结合HAVING
子句筛选分组结果。例如:-- 查询学生总数
SELECT COUNT(*)
FROM Student;
-- 求各个课程号及相应的选课人数
SELECT Cno, COUNT(Sno)
FROM SC
GROUP BY Cno;
-- 查询选修了3门以上课程的学生学号
SELECT Sno
FROM SC
GROUP BY Sno
HAVING COUNT(*)>3;
连接类型 | 语法特征 | 结果集包含内容 | 典型场景 |
---|---|---|---|
隐式内连接 | FROM 表1, 表2, ... WHERE 连接条件 |
仅包含所有表均满足连接条件的记录 | 查询学生及其对应课程的成绩(必须有选课记录) |
显式内连接 | FROM 表1 INNER JOIN 表2 ON 连接条件 |
同上(与隐式内连接完全等价,仅语法不同) | 同上,更推荐使用显式语法提高可读性 |
左外连接 | FROM 表1 LEFT OUTER JOIN 表2 ON 连接条件 |
包含左表所有记录,右表无匹配时字段为 NULL |
查询所有学生(包括未选课学生)及其课程成绩 |
右外连接 | FROM 表1 RIGHT OUTER JOIN 表2 ON 连接条件 |
包含右表所有记录,左表无匹配时字段为 NULL |
极少见(如以课程表为主,查询所有课程及选课学生) |
全外连接 | FROM 表1 FULL OUTER JOIN 表2 ON 连接条件 |
包含左右表所有记录,无匹配时字段为 NULL |
对比两张表数据完整性(如学生表与课程表的差异) |
-- 查询每个学生及其选修课程的情况(等值连接)
SELECT 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;
-- 查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno, SECOND.Cpno
FROM Course FIRST, Course SECOND
WHERE FIRST.Cpno=SECOND.Cno;
LEFT OUTER JOIN
)、右外连接(RIGHT OUTER JOIN
)、全连接(FULL JOIN
),用于保留特定表的所有行。NULL
填充。FROM table1 LEFT OUTER JOIN table2 ON table1.key = table2.key
(table1
为左表,table2
为右表,key
为连接条件 )。NULL
。NULL
。FROM table1 RIGHT OUTER JOIN table2 ON table1.key = table2.key
(table2
是右表,table1
是左表 )。NULL
填充。FROM table1 FULL JOIN table2 ON table1.key = table2.key
。原始 SQL 中的WHERE Student.Sno=SC.Sno(*)
使用了Oracle 旧版的外连接语法((*)
符号),这是 Oracle 数据库在 ANSI 标准之前的 proprietary 语法,用于表示左外连接。这种语法有几个问题:
现代 SQL 标准(ANSI)提供了统一的外连接语法:
-- 左外连接(保留左表所有记录,右表匹配不上的字段为NULL)
SELECT ...
FROM table1
LEFT OUTER JOIN table2 ON table1.key = table2.key;
-- 右外连接(保留右表所有记录,左表匹配不上的字段为NULL)
SELECT ...
FROM table1
RIGHT OUTER JOIN table2 ON table1.key = table2.key;
-- 全连接(保留左右表所有记录,匹配不上的字段为NULL)
SELECT ...
FROM table1
FULL OUTER JOIN table2 ON table1.key = table2.key;
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student
LEFT OUTER JOIN SC ON (Student.Sno=SC.Sno);
这个改写有以下改进:
LEFT OUTER JOIN
是 ANSI 标准语法,所有主流数据库都支持ON
子句)与过滤条件(WHERE
子句)明确分开,逻辑更清晰WHERE Student.Sno=SC.Sno(*)
功能完全相同,保留所有学生记录,无论是否有选课记录在学生 - 选课的场景中,左外连接是最常用的,因为业务需求通常是:
COALESCE(Grade, 0)
等函数进一步处理 NULL 值如果需要明确排除没有选课的学生,可以在左外连接后加 WHERE 过滤:
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,SC.Cno,Grade
FROM Student
LEFT OUTER JOIN SC ON Student.Sno=SC.Sno
WHERE SC.Sno IS NOT NULL; -- 只保留有选课记录的学生
这个查询实际上等价于内连接:
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,SC.Cno,Grade
FROM Student
INNER JOIN SC ON Student.Sno=SC.Sno;
-- 左外连接查询学生及其选修课程情况(ANSI标准)
SELECT Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade
FROM Student
LEFT OUTER JOIN SC ON (Student.Sno=SC.Sno);
-- 查询选修2号课程且成绩在90分以上的所有学生
SELECT Student.Sno, Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno AND
SC.Cno='2' AND
SC.Grade>90;
IN
、比较运算符、ANY
或ALL
、EXISTS
谓词的子查询,不同类型适用于不同场景,部分子查询可相互转换。例如:-- 带有IN谓词的子查询,查询与刘晨在同一个系学习的学生
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept IN (
SELECT Sdept
FROM Student
WHERE Sname='刘晨'
);
-- 带有比较运算符的子查询,重写上述查询
SELECT Sno,Sname,Sdept
FROM Student
WHERE Sdept = (
SELECT Sdept
FROM Student
WHERE Sname='刘晨'
);
UNION
(并)、INTERSECT
(交)、EXCEPT
(差)操作对查询结果集进行处理。例如-- 查询计算机科学系的学生及年龄不大于19岁的学生
SELECT *
FROM Student
WHERE Sdept='CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;
-- 查询计算机科学系中年龄不大于19岁的学生(交操作)
SELECT *
FROM Student
WHERE Sdept='CS'
INTERSECT
SELECT *
FROM Student
WHERE Sage<=19;
FROM
子句中生成临时表,作为主查询的对象。例如:-- 找出每个学生超过他自己选修课程平均成绩的课程号
SELECT Sno, Cno
FROM SC, (
SELECT Sno, AVG(Grade)
FROM SC
GROUP BY Sno
) AS Avg_sc(avg_sno,avg_grade)
WHERE SC.Sno=Avg_sc.avg_sno AND
SC.grade>=Avg_sc.avg_grade;
INSERT INTO...VALUES
语句,指定表名和列值。例如:-- 将一个新学生记录插入到Student表中
INSERT INTO Student
VALUES ('201215128','陈冬','男',18,'IS');
INSERT INTO...子查询
语句,将子查询结果插入表中。例如:-- 对每一个系,求学生的平均年龄,并把结果存入数据库
CREATE TABLE Deptage(Sdept CHAR(15), Avgage SMALLINT);
INSERT INTO Deptage(Sdept,Avgage)
SELECT Sdept,Avg(Sage)
FROM Student
GROUP BY Sdept;
UPDATE
语句,指定表名、修改的列和表达式,可带条件修改单个或多个元组。例如-- 将学生201215121的年龄改为22岁
UPDATE Student
SET Sage=22
WHERE Sno='201215121';
-- 将所有学生的年龄增加1岁
UPDATE Student
SET Sage=Sage+1;
DELETE FROM
语句,带条件删除单个或多个元组,注意数据一致性和事务处理。例如:-- 删除学号为201215128的学生记录
DELETE FROM Student
WHERE Sno='201215128';
-- 删除所有学生的选课记录
DELETE FROM SC;
视图(View)是数据库中一个虚表,它的数据来自一个或多个基本表(或其他视图),但本身不存储实际数据。数据库仅保存视图的定义(即查询逻辑),数据仍存放在原始表中。视图的作用类似于 “窗口”,通过特定逻辑筛选或重组数据,提供更简洁、安全的访问方式。
维度 | 视图 | 列表(结果集) |
---|---|---|
存储方式 | 不存储数据,仅保存定义 | 临时生成,不持久化 |
生命周期 | 持久化存在,直到被显式删除 | 查询结束后自动消失 |
可复用性 | 可重复使用,支持嵌套定义 | 每次查询需重新生成 |
数据独立性 | 屏蔽底层表结构变化,保护业务逻辑 | 直接依赖原始表结构 |
权限控制 | 可针对视图设置独立权限 | 依赖原始表权限,无法单独控制 |
简化复杂查询
将多表关联、过滤等复杂逻辑封装为视图,简化后续查询操作。
CREATE VIEW EmployeeSummary AS
SELECT e.id, e.name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.id;
提升安全性
通过视图限制用户访问字段或行,例如:
逻辑独立性
底层表结构变化时,只需修改视图定义,无需调整上层业务逻辑。
支持嵌套查询
可在视图基础上创建新视图,实现更复杂的逻辑分层。
优化性能
部分数据库(如 MySQL)会缓存视图执行计划,提升高频查询效率。
视图是数据库中重要的抽象工具,通过封装数据逻辑,平衡了灵活性、安全性和开发效率。适用于需要简化查询、保护数据或增强逻辑独立性的场景。
CREATE VIEW
语句,可带WITH CHECK OPTION
确保更新时满足视图条件,根据不同情况需指定视图列名。例如:-- 建立信息系学生的视图
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS';
-- 建立信息系学生的视图,并要求更新视图时仍保证视图只有信息系的学生
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS'
WITH CHECK OPTION;
DROP VIEW
语句。如DROP VIEW IS_S1;
,删除名为IS_S1
的视图。-- 在信息系学生的视图中找出年龄小于20岁的学生
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;
更新视图:部分视图可更新,行列子集视图通常允许更新,不同数据库系统对视图更新有更多限制。
常见不可更新情况
DB2
等系统规定此类视图不允许更新 。因为更新操作可能无法明确对应到具体某张表,造成数据不一致。INSERT
和 UPDATE
操作(但允许 DELETE
) 。比如视图字段是通过计算得到的表达式结果,更新会破坏表达式逻辑。SUM
、AVG
、COUNT
等 ),视图不允许更新 。集函数结果是统计汇总值,更新无实际意义且会破坏统计逻辑。GROUP BY
子句 ,不允许更新。GROUP BY
是分组统计操作,更新会使分组统计结果混乱。DISTINCT
短语 ,不允许更新。DISTINCT
用于去除重复行,更新可能破坏去重逻辑。FROM
子句涉及的表是导出该视图的基本表 ,不允许更新。这种复杂结构下更新难以保证数据一致性。例如:
-- 将信息系学生视图IS_Student中学号为200215122的学生姓名改为“刘辰”
UPDATE IS_Student
SET Sname='刘辰'
WHERE Sno='201215122';