数据库 - SQL

参考友情链接QAQ,写的很好:快速入门SQL

1. 模式

1.1 创建模式

sql 复制代码
-- 为用户 WANG 定义一个 学生-课程 模式 "S-T"
CREATE SCHEMA "S-T" AUTORIZATION WANG;

-- 模式名默认为用户名 WANG
CREATE SCHEMA AUTORIZATION WANG;

1.2 删除模式

sql 复制代码
-- CASCADE(级联):删除模式同时把该模式下所有数据库对象删除;
DROP SCHEMA TEST CASCADE;


-- RESTRICT(限制):如果该模式中定义了数据库对象,则拒绝执行;
-- RESTRICT 为缺省值;
DROP SCHEMA TEST RESTRICT;

2. 基本表

2.1 定义基本元素

数据类型

数据类型 表示内容
CHAR(n) 长度为n的字符型
VARCHAR(n) 最大长度为n的变长字符型
NUMBER(n) 长度为n的数字型
INT 长整型(4B)
SMALLINT 短整型(4B)
BIGINT 大整型(8B)
FLOAT(n) 精度至少为n位的浮点数
DATE 日期,格式为YYYY-MM-DD
TIME 时间,格式为HH:MM:SS

列级完整性约束

约束条件 意义
PRIMARY KEY 主码(元素唯一不能重复):当只有一个主码时,可直接在对应的属性列标注
NOT NULL 非空:表示该属性列不能取空值
UNIQUE 唯一值:表示该属性列只能取唯一值
CHECK 检查:检查该列是否满足某个条件,比如CHECK(某属性>20)

表级完整性约束

约束条件 意义
PRIMARY KEY(列名1,...,列名n) 多个主码:当主码由多个属性构成 时, 必须作为表级完整性定义
FOREIGN KEY(列名1) REFERENCES 被参照表(列名1) 外码:被参照的列必须是 PRIMARY KEYUNIQUE 约束 的列, 本表所有值来源于被参照的列

2.2 创建基本表

sql 复制代码
-- 当主码为单一属性,PRIMARY KEY 约束与 NOT NULL+UNIQUE 等效
CREATE TABLE Student
    (Sno CHAR(5) NOT NULL UNIQUE,
     Sname CHAR(20) UNIQUE,
     Ssex CHAR(2),
     Sage INT,
     Sdept CHAR(15),
     PRIMARY KEY(Sno));

-- 当主码为多属性,主码只能用 PRIMARY KEY 表级完整性约束
CREATE TABLE SC(
    Sno CHAR(5),
    Cno CHAR(3),
    Grade INT,
    PRIMARY KEY(Sno, Cno),
    FOREIGN KEY(Sno) REFERENCES Student(Sno),
    FOREIGN KEY(Cno) REFERENCES Course(Cno)); 

2.3 删除基本表

sql 复制代码
-- 级联,删除基本表的同时,相关依赖对象(视图,索引)一起删除
DROP TABLE Student CASCADE;

-- 限制,欲删除的表不能被其他表约束,也不能存在依赖对象
DROP TABLE Student RESTRICT;

2.4 修改基本表

sql 复制代码
-- 向 Student 表增加"入学时间"列,数据类型为 DATE
ALTER TABLE Student ADD entrance DATE;

-- 删除 entrance 列
ALTER TABLE Student DROP entrance;

-- 将年龄数据类型改为半字长整数
ALTER TABLE Student ALTER COULUMN Sage SMALLINT;

-- 删除/增加学生姓名必须取唯一值的约束
ALTER TABLE Student ADD/DROP UNIQUE(Sname);

2.5 索引

创建索引

sql 复制代码
-- Student 表按学号升序建单一索引
CREATE UNIQUE INDEX Stusno ON Student(Sno ASC);

-- Student 表按年龄降序建普通索引
CREATE INDEX Stusage ON Student(Sage DESC);

-- Course 表按课程号升序建单一索引,ASC 为缺省值
CREATE UNIQUE INDEX Cuncno ON Course(Cno);

-- SC 表按学号升序和课程号降序建单一索引
CREATE UNIQUE INDEX SCno ON SC(Sno, Cno DESC);

-- 在 Student 表的 Sname 列上建立一个聚簇索引,按 Sname 升序
CREATE CLUSTER INDEX Stusname ON  Student(Sname);

删除索引

sql 复制代码
-- 删除 Student 表的 Stusname 索引
DROP INDEX Stusname;

3. 单表查询

  • 需要用到的三张基本表:
  • 学生表 Student(Sno,Sname,Ssex,Sage,Sdept):

|-------|-------|------|------|-------|
| Sno | Sname | Ssex | Sage | Sdept |
| 95001 | 李勇 | 男 | 20 | CS |
| 95002 | 刘晨 | 女 | 19 | IS |
| 95003 | 王敏 | 女 | 18 | MA |
| 95004 | 张立 | 男 | 19 | IS |
| ... | ... | ... | ... | ... |

  • 课程表: Course(Cno,Cname,Cpno,Ccredit):

|-----|----------|------|---------|
| Cno | Cname | Cpno | Ccredit |
| 1 | 数据库 | 5 | 4 |
| 2 | 数学 | NULL | 2 |
| 3 | 信息系统 | 1 | 4 |
| 4 | 操作系统 | 6 | 3 |
| 5 | 数据结构 | 7 | 4 |
| 6 | 数据处理 | NULL | 2 |
| 7 | PASCAL语言 | 6 | 4 |
| ... | ... | ... | ... |

  • 学生选课表: SC(Sno,Cno,Grade):

|-------|-----|-------|
| Sno | Cno | Grade |
| 95001 | 1 | 92 |
| 95001 | 2 | 65 |
| 95001 | 4 | 88 |
| 95002 | 2 | 90 |
| 95002 | 5 | 73 |
| ... | ... | ... |

3.0 SQL 查询逻辑执行顺序

sql 复制代码
-- 从哪查 -> 过滤行 -> 分组 -> 过滤组 -> 选择数据 -> 选择排列顺序 
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY

3.1 SELECT

sql 复制代码
-- 查询全体学生的学号和姓名
SELECT Sno, Sname
FROM Student;

-- 查询全体学生全部信息
SELECT *
FROM Student;

-- 表达式,列别名
SELECT Sname NAME, 'Year of Birth:' BIRTH, 2025-Sage BIRTHDAY, LOWER(Sdept) DEPARTMENT
FROM Student;

-- 去重:查询选修了课程的学生学号
SELECT DISDINCT Sno
FROM SC;

-- DISDINCT 作用于所有目标列:查询选修各门课程的各种成绩
SELECT DISDINCT Cno, Grade
FROM SC;

3.2 WHERE(Step1 过滤行)

  • 比较运算符
sql 复制代码
-- 查询计算机系全体学生信息
SELECT *
FROM Student
WHERE Sdept='CS';

-- 查询所有年龄在 20 岁以下的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sage < 20;
  • 确定范围
sql 复制代码
-- 查询所有年龄在 20~23 的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sage BETWEEN 20 AND 23;
  • 确定集合
sql 复制代码
-- 查询 IS,MA,CS 系学生姓名和性别
SELECT Sname, Ssex
FROM Student
WHERE Sdept IN ('IS','MA','CS');

-- 查询不是 IS,MA,CS 系学生姓名和性别
SELECT Sname, Ssex
FROM Student
WHERE Sdept NOT IN ('IS','MA','CS');
  • 字符串匹配
sql 复制代码
-- 通配符:% 代表任意长度,_ 代表单个字符
-- 转义字符:ESCAPE'<换码字符>'

-- 查询学号为 95001 的学生信息
SELECT *
FROM Student
WHERE Sno LIKE 95001;

-- 查询姓名中第二个字为"阳"的学生姓名和学号
SELECT Sname, Sno
FROM Student
WHERE Sname LIKE '_阳%';

-- 查询所有不姓刘的学生姓名
SELECT Sname
FROM Student
WHERE Sname NOT LIKE '刘%';

-- 查询以"DB_"开头,倒数第三个字符为 i 的课程信息
SELECT *
FROM Course
WHERE Cname LIKE 'DB\_%i__' ESCAPE'\';
  • 涉及空值
sql 复制代码
-- 使用谓词 IS NULL / IS NOT NULL
-- 查询缺少成绩的学生的学号和课程号
SELECT Sno, Cno
FROM SC
WHERE Grade IS NULL;
  • 多重条件
sql 复制代码
-- 优先级:NOT > AND > OR,可以用括号改变优先级
-- 查询计算机系 20 岁以下学生姓名
SELECT Sname
FROM Student
WHERE Sdept='CS' AND Grade<20;

-- 查询 IS,MA,CS 系学生姓名和性别
SELECT Sname, Ssex
FROM Student
WHERE Sdept='IS' OR Sdept='MA' OR Sdept='CS';

3.3 ORDER BY

sql 复制代码
-- 查询选修了 3 号课程的学生的学号和成绩,结果按分数降序排列
SELECT Sno, Grade
FROM SC
WHERE Cno='3'
ORDER BY Grade DESC;

-- 查询全体学生信息,结果按系名升序排列,同系按年龄降序排列
SELECT *
FROM Student
ORDER BY Sdept, Sage DESC;

3.4 集函数

  • 集函数可以出现在:SELECT、HAVING、ORDER BY、子查询中;
  • 集函数不能出现在:WHERE、GROUP BY 中直接使用;
  • 有无 GROUP BY 的区别:
    • 有 GROUP BY:按组聚合,返回多行;
    • 无 GROUP BY:全局聚合,返回单行;
sql 复制代码
-- 查询学生总人数
SELECT COUNT(*)
FROM Student;

-- 查询选修了课程的总人数,用 DISTINCT 避免重复
SELECT COUNT(DISTINCT Sno)
FROM SC

-- 查询选修了 1 号课程的学生最高分
SELECT MAX(Grade)
FROM SC
WHERE Cno='1';

-- 查询学生 95002 选修课程的总学分
SELECT SUM(Ccredit)
FROM SC, Course
WHERE Sno='95002' AND SC.Sno=Course.Sno;

3.5 GROUP BY - HAVING(Step2 过滤组)

  • 使用GROUP BY子句后,SELECT子句的列名列表中只能出现分组属性和集函数;
  • WHERE 过滤行,HAVING 过滤组,先 WHERE 后 GROUP BY 再 HAVING;
sql 复制代码
-- 求各个课程号及相应的选课人数
SELECT Cno, COUNT(Sno)
FROM SC
GROUP BY Cno;

-- 查询选修了超过 3 门课程的学生学号
SELECT Sno
FROM SC
GROUP BY Sno HAVING COUNT(*)>3;

-- 查询有多于 3 门课程是 90 分以上的学生学号及课程数
SELECT Sno, COUNT(*)
FROM SC
WHERE Grade>90                    -- 先筛成绩 90 分以上的记录
GROUP BY Sno HAVING COUNT(*)>3;   -- 再筛课程数大于 3 的学生

4. 连接查询

4.1 两表连接

sql 复制代码
-- 查询每个学生及其选修课信息
SELECT Student.*, SC.*
FROM Student, SC
WHERE Student.Sno=SC.Sno;

4.2 自身连接

sql 复制代码
-- 查询每一门课的间接先修课,需要给表起别名
SELECT FIRST.Cno, SECOND.Cpno
FROM Course FIRST, Course SECOND
WHERE FIRST.Cpno=SECOND.Cno;

4.3 外连接

  • 左外连接保留左表的所有记录,并尽可能地匹配右表中的记录 右外连接保留右表的所有记录,并尽可能地匹配左表中的记录
  • 将悬浮元组保留在结果关系中,没有属性值的位置填上NULL;
  • SELECT 列名 FROM 表名1 LEFT OUTER JOIN 表名2 ON(连接条件)
  • SELECT 列名 FROM 表名1 RIGHT OUTER JOIN 表名2 ON(连接条件)
sql 复制代码
-- 查询每个学生及其选修课程的情况
SELECT Student.*, Cno, Grade
FROM Student LEFT OUTER JOIN SC
ON Student.Sno=SC.Sno

-- 或
SELECT Student.*, Cno, Grade
FROM Student LEFT OUTER JOIN SC
USING(Sno)

4.4 复合条件连接

sql 复制代码
-- 查询选修 2 号课程且成绩在 90 以上的学生的学号和姓名
SELECT Student.Sno, Student.Sname
FROM Student, SC
WHERE Student.Sno=SC.Sno AND -- 连接条件
      SC.Cno='2' AND         -- 选择条件
      SC.Grade>=90;          -- 选择条件

-- 查询每个学生的学号,姓名,选修的课程名及成绩
SELECT Student.Sno, Sname, Cname, Grade
FROM Student, SC, Course
WHERE Student.Sno=SC.Sno AND 
      SC.Cno=Course.Cno;     -- 三张表需要两个连接条件 

5. 嵌套查询(两层 for 循环)

  • 子查询不能使用 ORDER BY 子句;

5.1 IN 子查询

sql 复制代码
-- 查询与"刘晨"在同一个系学习的学生(学号,姓名,系别)

-- step1. 确定"刘晨"所在系名
SELECT Sdept
FROM Student
WHERE Sname='刘晨';

-- step2. 查找所有在 IS 系学习的学生
SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept='IS';

-- 嵌套
SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept IN
    (SELECT Sdept
     FROM Student
     WHERE Sname='刘晨');
sql 复制代码
-- 查询选修了课程名为"数据库"的学生学号和姓名
SELECT Sno, Sname
FROM Student
WHERE Sno IN                    -- 最后在 Student 查询
    (SELECT Sno
     FROM SC
     WHERE Cno IN               -- 再在 SC 找选修了该课程的学生学号
        (SELECT Cno
         FROM Course
         WHERE Cname='数据库')  -- 先在 Course 找"数据库"课程号

5.2 比较运算符子查询

  • 若内层查询返回单值,可用比较运算符;
sql 复制代码
-- 查询与"刘晨"在同一个系学习的学生
SELECT Sno, Sname, Sdept
FROM Student
WHERE Sdept =
    (SELECT Sdept
     FROM Student
     WHERE Sname='刘晨');
  • 同表关联要别名,先写逻辑后关联;
sql 复制代码
-- 找出每个学生超过他选修课平均分的课程号
SELECT Sno, Cno
FROM SC X
WHERE Grade >= 
    (SELECT AVG(Grade)
     FROM SC Y            -- 相关子查询,取别名
     WHERE Y.Sno=X.Sno)

5.3 ANY / ALL 子查询

  • ANY:某些值;ALL:所有值;
sql 复制代码
-- 查询其他系中比IS系某些学生年龄小的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sage < ANY(SELECT Sage
                 FROM Student
                 WHERE Sdept='IS') -- 先找出IS系中所有年龄构成的集合
      AND Sdept<>'IS';

-- 也可以用集函数实现
SELECT Sname, Sage
FROM Student
WHERE Sage < (SELECT MAX(Sage)
              FROM Student
              WHERE Sdept='IS') 
      AND Sdept<>'IS';

-- 查询其他系中比IS系所有学生年龄小的学生姓名和年龄
SELECT Sname, Sage
FROM Student
WHERE Sage < ALL(SELECT Sage
                 FROM Student
                 WHERE Sdept='IS') 
      AND Sdept<>'IS';

-- 也可以用集函数实现
SELECT Sname, Sage
FROM Student
WHERE Sage < (SELECT MIN(Sage)
              FROM Student
              WHERE Sdept='IS') 
      AND Sdept<>'IS';

5.4 EXISTS 子查询

  • EXISTS 为存在量词,对应 NOT EXISTS;
  • EXISTS 子查询不返回任何数据,结果非空返回 true,结果为空返回 false;
sql 复制代码
-- 查询所有选修了 1 号课程的学生姓名
SELECT Sname
FROM Student
WHERE EXISTS
    (SELECT *           -- 由EXISTS引出的子查询,其目标列表达式通常都用*
     FROM SC
     WHERE Sno=Student.Sno AND Cno='1') -- 找到第一条匹配就返回

-- 查询没有选修 1 号课程的学生姓名
SELECT Sname
FROM Student
WHERE NOT EXISTS
    (SELECT *           
     FROM SC
     WHERE Sno=Student.Sno AND Cno='1') 
sql 复制代码
-- 查询选修了全部课程的学生(等价于不存在一门课没有选修)
SELECT Sname
FROM Student
WHERE NOT EXISTS
    (SELECT *                 -- 对课程号进行对比,匹配是否有没选修的课程号
     FROM Course
     WHERE NOT EXISTS
        (SELECT *             -- 查询该学生选修了的课程号
         FROM SC
         WHERE Sno=Student.Sno AND Cno=Course.Cno));

6. 集合查询

6.1 并操作(UNION)

sql 复制代码
-- 查询CS系的学生和年龄不大于19的学生
SELECT *
FROM Student
WHERE Sdept='CS'
UNION
SELECT *
FROM Student
WHERE Sage<=19;

-- 法二:单表查询
SELECT *
FROM Student
WHERE Sdept='CS' OR Sage<=19;

6.2 交操作(INTERSECT)

sql 复制代码
-- 查询选修了课程1和课程2的学生学号
SELECT Sno
FROM SC
WHERE Cno='1'
INTERSECT
SELECT Sno
FROM SC
WHERE Cno='2';

-- 法二:连接查询(SC自身连接)
SELECT Sno
FROM SC X, SC Y
WHERE X.Sno=Y.Sno AND X.Cno='1' AND Y.Cno='2';

6.3 查操作(EXCEPT)

sql 复制代码
-- 查询CS系年龄不大于19岁的学生学号
SELECT Sno
FROM Student
WHERE Sdept='CS'
EXCEPT
SELECT Sno
FROM Student
WHERE Sage>19;

-- 法二:单表查询
SELECT Sno
FROM Student
WHERE Sdept='CS' AND Sage<=19;

7. 数据更新

7.1 INSERT 插入

插入单个元组

sql 复制代码
-- 插入一个新学生信息
INSERT
INTO Student
VALUES('95020','陈冬','男',18,'IS');

-- 插入一个选课记录('95020','1')
INSERT
INTO SC(Sno, Cno)
VALUES('95020','1')   -- Grade 取空

插入子查询结果

sql 复制代码
-- 对每一个系,求学生平均年龄,并存入数据库
INERT
INTO Deptage(Sdept, Avgage)
SELECT Sdept, AVG(Sage)
FROM Student
GROUP BY Sdept;

7.2 UPDATE 修改

sql 复制代码
-- 将学生95001的年龄改为22岁
UPDATE Student
SET Sage=22
WHERE Sno='95001';

-- 将IS系所有学生的年龄增加1岁
UPDATE Student
SET Sage=Sage+1
WHERE Sdept='IS';

-- 将CS系所有学生成绩清零
UPDATE SC
SET Grade=0
WHERE Sno IN
    (SELECT Sno
     FROM Student
     WHERE Sdept='CS');

7.3 DELETE 删除

sql 复制代码
-- 删除学号95019的学生记录
DELETE
FROM Student
WHERE Sno='95019';

-- 删除2号课程所有选课记录
DELETE
FROM SC
WHERE Cno='2';

-- 删除所有选课记录
DELETE
FROM SC

-- 删除CS系所有学生的选课记录
DELETE
FROM SC
WHERE Sno IN
    (SELECT Sno
     FROM Student
     WHERE Sdept='CS');

8. 视图

8.1 建立视图

  • 若添加WITH句,则表示对视图进行增删改时要满足子查询中的条件表达式;
  • 行列子集视图:由单个基本表导出,仅去掉了基本表的某些行和某些列,但保留了主码;
sql 复制代码
-- 建立IS系学生视图
CREATE VIEW IS_Student
AS
SELECT Sno,Sname,Sage
FROM Student
WHERE Sdept='IS';
WITH CHECK OPTION;   -- 如果要求透过该视图的更新操作只涉及IS系学生,需要加这句
                     -- 更新后每一行都应满足 Sdept='IS' 条件

-- 建立信息系选修1号课程的学生视图(学号,姓名,成绩)
CREATE VIEW IS_S1(Sno,Sname,Grade)
AS
SELECT Student.Sno,Sname,Grade
FROM Student, SC
WHERE Sdept='IS' AND Student.Sno=SC.Sno AND SC.Cno='1';

-- 建立信息系选修1号课程且成绩在90以上的学生视图
CREATE VIEW IS_S2(Sno,Sname,Grade)
AS
SELECT Sno,Sname,Grade
FROM IS_S1
WHERE Grade>=90;

-- 定义一个反映学生出生年份的视图
CREATE VIEW BT_S(Sno,Sname,Sbirth)
AS
SELECT Sno,Sname,2025-Sage
FROM Student

-- 将学生学号,平均成绩定义为一个视图
CREATE VIEW S_G(Sno,Gavg)
AS
SELECT Sno,AVG(Grade)
FROM SC
GROUP BY Sno;

8.2 删除视图

sql 复制代码
-- 如果在视图IS_S1上建立了视图IS_S2,需要先删除IS_S2
DROP VIEW IS_S2;

-- 或
DROP VIEW IS_S1 CASCADE;

8.3 查询和更新视图

  • 视图定义后,对视图进行查询和更新的语句和语法与基本表相同;
  • 视图的查询与更新最终都会转换为对基本表的查询和更新,这一过程也被称为视图消解;
  • 一般来说,行列子集视图的查询和更新都可以顺利转换,其他则不一定;
sql 复制代码
SELECT Sno,Sage
FROM Student
WHERE Sdept='IS' AND Sage<20;

-- 利用视图
SELECT Sno,Sage
FROM IS_Student
WHERE Sage<20;
相关推荐
百***62852 小时前
oracle 12c查看执行过的sql及当前正在执行的sql
java·sql·oracle
不会c嘎嘎2 小时前
MySQL -- 库的操作
数据库·mysql
陌上桑花开花2 小时前
DBeaver常用配置
数据库
百***87442 小时前
MySQL 查看有哪些表
数据库·mysql·oracle
曹牧2 小时前
Oracle:查询当前正在等待执行的SQL语句
linux·数据库·oracle
_Kafka_2 小时前
在 Oracle Data Guard 环境中,手工将备库(Standby)切换为主库(Primary)
数据库·oracle
百***24132 小时前
oracle使用PLSQL导出表数据
数据库·oracle
cqsztech2 小时前
ORACLE 11g 在线修改数据文件路径
数据库·oracle
为什么要做囚徒2 小时前
Oracle跨用户表授权+同义词创建的标准脚本模板
数据库·oracle