特点

  • 高度统一:集DDL,DML,DCL于一体
  • 高度非过程化:只需要提出做什么,无需声明怎么做
  • 面向集合的操作:操作的对象和结果均为集合
  • 两种使用方法:自主式使用(CLI,GUI),嵌入式语言

核心命令

  1. DDL:CREATE DROP ALERT
  2. DML: SELECT INSERT UPDATE DELETE
  3. DCL: GRANT REVOKE

数据类型

数据类型 声明
数字 NUMERIC,DECIMAL, INTERGER,SMALLINT,FLOAT,DOUBLE,REAL
字符串 CHAR, VARCHAR, TEXT
二进制串 BINARY,VARBINARY,BLOB
布尔类型 BOOLEAN
日期时间 DATE,TIME,DATETIME,TIMESTAMP
时间间隔 INTERVAL
XML文本 XML

聚集函数

聚集函数可以直接对查询结果进行统计 但是只能出现在SELECT的后面,而且只会返回一个元组

函数 返回值
CHAR_LENGTH(string) 字符串长度
LOWER(string) 字符串全部转换为小写
UPPER(string) 字符串全部转换为大写
SUBSTRING(source, n, len) 取长度为len的子串
MAX(column) 制定列的最大值
MIN(column) 制定列的最小值
AVG(column) 制定列的平均值
SUM(column) 制定列的总和
CURRENT_DATE() 当前日期
COUNT(*) 计算总行数
COUNT(EXP) 计算非空行数

与关系代数的联系

关系运算符 SQL关键字
选择 WHERE
投影 SELECT
笛卡尔积 FROM

数据查询

关键字

类型 命令
无条件查询 SELECT... FROM
条件查询 SELECT...FROM...WHERE
列的别名 ... AS ...
带表达式的查询 SELECT
字符串匹配 LIKE
结果去重 DISTINCT
结果排序 ORDER BY

无条件查询

SQL语句:SELECT <字段列表> FROM <表名>

可以用*表示所有列名;

例如查询所有医生的信息:

1
SELECT * FROM Doctor;

结果如下:

image-20241027123444923

条件查询

SQL语句:SELECT <字段列表> FROM <表名> WHERE <查询条件>

条件之间的连接可以使用以下的连接运算符:

image-20241027123645997

例如:查询年龄小于或等于40岁的男医生信息

1
SELECT *  FROM  Doctor  WHERE Dsex='男' AND Dage<=40 ;

结果如下:

image-20241027123844916

列的别名

改变查询显示列的标题,用关键字AS,跟在SELECT的属性后面;

SQL语句:SELECT <字段1> AS <别名1>,..., <字段吗> AS <别名m> FROM <表名>

例:查询医生姓名和职称并重命名

1
SELECT Dname AS 医生姓名, Dlevel 专业职称 FROM Doctor;

结果如下:

image-20241027124146262

查询表达式

查询条件可以用表达式表示

例:在药品信息表中,查询药品单价提高15%后超过30元的药品信息

1
SELECT Mno 编号,Mname 药品名,Mprice 单价,Mprice*1.15 调整单价 FROM medicine  WHERE Mprice*1.15>=30;

字符串匹配

字符串的模式匹配:正则表达式支持

  • %:表示任意长度(包括长度为0)的字符串
  • _:表示任意单个字符

例如:查询职称为副某的医生信息

1
SELECT *  From Doctor  Where Dlevel Like '副%';

结果去重

使用DISTINCT合并查询结果的重复记录

例如:查询部门编号

1
SELECT DISTINCT Ddeptno FROM Doctor; 

结果排序

使用ORDER BY

  • 系统缺省为升序排序ASC
  • 也可以设定为降序DESC

例如:按部门编号升序而按年龄降序查询医生信息

1
SELECT * From Doctor  ORDER BY Ddeptno ASC ,Dage DESC ;

统计查询

统计查询是通过聚集函数实现的;它可以对查询结果直接进行统计;

  • 聚集函数一般忽略空值;
  • 选项DISTINCT表示只计算不同的记录值,不计入重复值和空行;
  • 一次聚集函数返回一条记录

分组查询:使用GROUP BY,对所查询的表按字段进行分组,值相同的在一组,和聚集函数一起使用,聚集函数对每一组产生一个统计结果

分组筛选:使用HAVING子句,选出复合条件的统计分组,放在GROUPBY子句后

例如:

查询申请了计算机专业总申请数量

查询各个专业总申请数量;

计算机专业申请者数量大于等于2的高校;

1
2
3
SELECT COUNT(*) FROM Apply WHERE Major='计算机';
SELECT COUNT(*) FROM Apply sID cID GROUP BY major;
SELECT cID, COUNT(DISTINCT sID) FROM Apply WHERE Major='计算机' GROUP BY cID HAVING COUNT(DISTINCT sID) >=2;

连接查询

连接满足查询条件或结果来自多个表; 连接同名之短时需要消除歧义; 连接条件的不同特点:等值连接,非等值连接,自然连接,自连接

内连接

找出符合条件的共有记录,

  • FROM R1, R2 WHERE R1.A1 <比较运算符> R2.A2
  • FROM R1 INNER JOIN R2 ON + R1.A1 <比较运算> R2.A2
  • FROM R1 INNER JOIN R2 USING(A1)

等值连接

例如: 在医生基本信息表中,需要查询患者的每个处方用药信息;

1
SELECT RecipeDetail.* Medicine.* FROM RecipeDetail, Medicine WHERE RecipeDetail.Mno=Medicine.Mno;

自然连接

要求连接列的列名相同,并且查询结果列不重复 NATURE JOIN 例如:在医院信息数据库中,需要查询开出处方的医生信息。

1
2
3
4
SELECT Rno,Pno,Dno,Dname,Dsex,Dage,Ddeptno,Dlevel
FROM RecipeMaster R NATUAL JOIN Doctor D
FROM RecipeMaster R NATUAL JOIN Doctor D
SELECT Rno,Pno,D.Dno,Dname,Dsex,Dage,Ddeptno,Dlevel

自连接

支持表自身的连接,即同一张表的两个副本之间的连接 例如:在医院部门表中,需要医院的各部门名称和上级部门名称

1
2
3
SELECT First.DeptName 部门名称,Second.DeptName 上级部门
FROM Dept First ,Dept Second
WHERE First.ParentDeptNo=Second.DeptNo

外连接

左外连接:LEFT OUTER JOIN 右外连接:RIGHT OUTER JOIN 全外连接:FULL OUTER JOIN 不一定所有数据库支持外连接;

嵌套查询

在一个查询语句中包含另一个完整的查询语句; 外层的查询:父查询 内层的查询:子查询 子查询的结果作为主查询条件的一部分;

  • 不相关子查询:子查询条件不依赖于主查询,独立执行,顺序从内至外;
  • 相关子查询:子查询依赖于主查询,子查询需要引用主查询的表 例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT sID,sName,GPA
FROM Student NATURAL JOIN Apply
WHERE cID=10614AND GPA>
SELECT AVG(GPA)
FROM Student NATURAL JOIN Apply
WHERE cID=10614’);

SELECT sID,sName,GPA
FROM Student NATURAL JOIN Apply A
WHERE AND GPA>
SELECT AVG(GPA)
FROM Student NATURAL JOIN Apply B
WHERE A.cID=B.cID);

子查询结果是一个关系,可以利用集合运算符

  • IN/NOT IN: 测试一个元素是否属于一个集合
  • EXISTS/NOT EXISTS:测试一个集合是否为空
  • 关键字在父查询的FROM子后
1
2
3
4
5
6
7
8
9
SELECT sName FROM Student 
WHERE sID
IN
( SELECT sID FROM Apply
WHERE major=‘计算机’);
SELECT sName FROM Student S1
WHERE NOT EXISTS
( SELECT * FROM Student S2
WHERE S2.GPA>S1.GPA);

谓词

  • 与集合所有元素比较ALL 例如GPA最高的学生姓名SELECT sName FROM Student WHERE GPD >= ALL (SELECT GPA FROM Student)
  • 与集合中任意一个元素比较 例如GPA最高的学生姓名SELECT sName FROM WHERE NOT GPA < ANY (SELECT GPA FROM Student)

应该优先选择子查询而不是连接查询

  • 查询多次带来的IO开销不可忽略
  • 连接查询在内部有查找优化(索引+二分),性能并不是线性相乘

数据更新

插入操作

引入关键字:INSERT INTO … VALUES 格式如下

  • 表名:指要插入数据的目标表
  • 列名:指定表的目标列,参数省略时默认全部列
  • 值表:具体要插入的值
1
INSERT INTO <表名> [(<列名>)] VALUES (<值表>)

增加操作

格式为

  • select子句中选择的列应该和列名保持对应
  • 类型和长度兼容,列名可以不同
1
INSERT INTO <表名> [(<列名>)] <select子句>

修改操作

引入关键字UPDATE 格式为

1
2
3
UPDATE <表名> 
SET <1>=<表达式1>, <2>=<表达式2>,…
[WHERE]

数据删除

引入关键字DELETE 格式为

1
DELETE FROM <表名> WHERE <条件>