1. 前言 & 环境启动
在上一篇《SQLite语法学习:HAVING、DISTINCT、JOIN、UNION子句》 中,讲解了 SQLite的HAVING、DISTINCT、JOIN、UNION子句语法,在本篇博客中,将继续讲解 SQLite 触发器、视图、索引和子查询的基本语法。
同学们将学习到:
- SQLite 触发器语法
- SQLite 视图语法
- SQLite 索引语法
- SQLite 子查询语法
请同学们参考《SQLite3快速入门:SQLite 是什么?如何用好 TA?》 ,完成 SQLite 的环境启动,具体命令如下。
cd 你的 SQLite 目录
sqlite3
.open test.db
启动成功后,如下图所示。
请同学初始化本次博客中需要用到的数据,命令如下。
CREATE TABLE student(
code CHAR(100) PRIMARY KEY,
name CHAR(100),
age INT(100),
mobile CHAR(100),
honor TEXT
);
INSERT INTO student VALUES ('002', '李四', 18,'17800000002','期中进步生');
INSERT INTO student VALUES ('003', '王五', 19,'17800000003','蓝桥杯省级三等奖');
INSERT INTO student VALUES ('004', '赵六', 20,'17800000004','程序设计竞赛一等奖');
INSERT INTO student VALUES ('005', '郑七', 19,'17800000005','蓝桥杯省级一等奖');
INSERT INTO student VALUES ('006', '皱八', 21,'17800000006','数学竞赛二等奖');
INSERT INTO student VALUES ('007', '龚九', 19,'17800000007','蓝桥杯省级二等奖');
INSERT INTO student VALUES ('008', '桑十', 22,'17800000008','蓝桥杯省级三等奖');
INSERT INTO student VALUES ('009', '武十一', 18,'17800000009','数学建模竞赛三等奖');
INSERT INTO student VALUES ('010', '揣十二', 17,'17800000010','蓝桥杯省级二等奖');
INSERT INTO student VALUES ('011', '周十三', 23,'17800000011','蓝桥杯省级参与奖');
INSERT INTO student VALUES ('012', '钟十四', 27,'17800000012','蓝桥杯省级一等奖');
INSERT INTO student VALUES ('013', '孟十五', 30,'17800000013','蓝桥杯省级参与奖');
INSERT INTO student VALUES ('014', '梁十六', 15,'17800000014','蓝桥杯省级三等奖');
CREATE TABLE achievement(
id INTEGER PRIMARY KEY AUTOINCREMENT ,
code CHAR(100),
examination CHAR(100),
grade DOUBLE,
date CHAR(100)
);
INSERT INTO achievement VALUES (1, '001', '高等数学A', 91.5,'2023-01-28');
INSERT INTO achievement VALUES (2, '002', '高等数学A', 88.0,'2023-01-28');
INSERT INTO achievement VALUES (3, '003', '高等数学A', 70,'2023-01-28');
INSERT INTO achievement VALUES (4, '004', '高等数学A', 55.5,'2023-01-28');
INSERT INTO achievement VALUES (5, '001', 'C语言程序设计', 71.5,'2023-01-28');
INSERT INTO achievement VALUES (6, '002', 'C语言程序设计', 51.5,'2023-01-28');
INSERT INTO achievement VALUES (7, '003', 'C语言程序设计', 91.5,'2023-01-28');
INSERT INTO achievement VALUES (8, '004', 'C语言程序设计', 81.5,'2023-01-28');
CREATE TABLE log(
id INTEGER PRIMARY KEY AUTOINCREMENT,
mobile CHAR(100),
time CHAR(100)
);
上面的命令创建了学生表,拥有学号( c o d e code code)、姓名( n a m e name name)、年龄( a g e age age)、手机号( m o b i l e mobile mobile)、荣誉( h o n o r honor honor)这五个字段,并初始化了 14 14 14 条数据。
创建了学生成绩表,拥有成绩 ID( i d id id)、学号( c o d e code code)、考试名称( e x a m i n a t i o n examination examination)、成绩( g r a d e grade grade)、录入日期( d a t e date date)这五个字段,并初始化了 8 8 8 条数据。
另外也创建了日志表,拥有日志 ID( i d id id)、手机号( d a t a data data)、记录时间( t i m e time time)这三个字段。
初始化结果如下图所示。
2 触发器
SQLite 的触发器是数据库的回调函数,它会在指定的数据库事件发生时自动执行/调用。
简单来说,触发器就是 sqlite
数据的监听事件,当被触发后可以做一定事情。
触发器的基本语法如下所示。
CREATE TRIGGER 触发器名称 [BEFORE|AFTER] 事件类型
ON 表名
BEGIN
-- 执行的事件
END;
同学们需要注意以下几点:
- 触发器只能在 DELETE、INSERT 或 UPDATE 时被触发,或在一个或多个指定表的列发生更新时触发。
- SQLite 只支持 FOR EACH ROW 触发器,不支持 FOR EACH STATEMENT 触发器。
- WHEN 子句和触发器动作可能访问使用表单 NEW.column-name 和 OLD.column-name 的引用插入、删除或更新的行元素,其中 column-name 是从与触发器关联的表的列的名称。
- 如果提供 WHEN 子句,则只针对 WHEN 子句为真的指定行执行 SQL 语句;如果没有提供 WHEN 子句,则针对所有行执行 SQL 语句。
- 事件类型就是 BEFORE 或 AFTER,判断是在插入、修改或删除之前或者之后执行触发器。
- 当触发器相关联的数据表被删除时,系统会自动删除触发器。
- 要修改的表必须存在于同一数据库中,作为触发器被附加的表或视图,且必须只使用 tablename,而不是 database.tablename。
- 一个特殊的 SQL 函数 RAISE() 可用于触发器程序内抛出异常。
例题1:在新增学生的数据时,需要自动将输入手机号存储在日志表,则需要定义以下触发器。
CREATE TRIGGER mobile_log AFTER INSERT
ON student
BEGIN
INSERT INTO log(mobile, time) VALUES (new.mobile, datetime('now'));
END;
请注意:命令需要逐行执行,不能一次全部复制执行!
触发器创建完成后,首先查询一次日志表,命令如下。
SELECT * FROM log;
查询发现没有数据,接着新增一位学生,请同学们执行以下插入命令。
INSERT INTO student VALUES ('001', '张三', 17,'17800000001','市三好学生');
此时再次查询日志表的数据,命令如下。
SELECT * FROM log;
发现日志数据已生成,如下图所示,说明触发器已成功执行。
3 视图
在实战开发中,数据库的设计往往追求 高内聚低耦合,尽可能追求高等级的范式。
但在产品应用时,客户往往需要更直观的表示,如学生姓名、手机号、宿舍房号、班主任姓名等数据放在一张表中展示。
但在数据库中,会设立学生表、宿舍分配表、班级档案表等多张数据表。
为了解决此类问题,sqlite
提供了视图,用于生成各类报表,接下来对视图进行讲解。
-
视图是通过相关的名称存储在数据库中的一个 SQLite 语句。
-
视图是一个以预定义的 SQLite 查询形式存在的表的组合。
-
视图可以包含一个表的所有行或从一个或多个表选定行。
-
视图可以从一个或多个表创建,这取决于要创建视图的 SQLite 查询。
-
视图是一种虚表,没有物理存储空间。
3.1 创建视图
SQLite 视图可以从一个单一的表、多个表或其他视图创建,基本语法如下。
CREATE [TEMP | TEMPORARY] VIEW 视图名称 AS
SELECT 视图列1, 视图列2.....
FROM 表名
WHERE [条件];
比如需要对高于 60 60 60 分的学生数据进行分析,包括学号、姓名、考试名称和成绩,创建一个数据展示视图,命令如下。
CREATE VIEW my_view AS
SELECT s.code, s.name, a.examination,a.grade
FROM student s,achievement a
WHERE s.code = a.code and a.grade >= 60;
提示:请逐行复制执行命令。
3.2 查询视图
视图也是一张虚拟的表,同学们可以使用 SELECT
子句完成对视图的查询,命令如下。
SELECT * FROM my_view;
查询结果如下图所示。
3.3 删除视图
视图是一张临时的虚拟表,在视图使用完成后,同学们应及时的删除视图,避免资源的浪费。
删除视图的基本语法如下。
DROP VIEW 视图名;
比如要删除创建的 my_view
视图,命令如下。
DROP VIEW my_view;
执行后,视图将被删除。
4 索引
索引是一种特殊的查找表,数据库搜索引擎用来加快数据检索。
简单地说,索引是一个指向表中数据的指针。
一个数据库中的索引与一本书后边的索引是非常相似的。
索引有助于加快 SELECT 查询和 WHERE 子句,但它会减慢使用 UPDATE 和 INSERT 语句时的数据输入,在实战开发中应根据情况使用。
索引可以创建或删除,且不会对现有数据产生影响。
在 sqlite
中,索引可以分为以下 4 4 4 种:
- 单列索引:是一个只基于表的一个列上创建的索引。
- 唯一索引:不允许任何重复的值插入到表中,性能较高,保证了数据的完整性。
- 组合索引:是基于一个表的两个或多个列上创建的索引。
- 隐式索引:数据库服务器自动创建的索引,如主键、外键、唯一键等。
4.1 创建索引
创建单列索引的基本语法如下。
CREATE INDEX 索引名
ON 表名 (索引列名);
创建唯一索引的基本语法如下。
CREATE UNIQUE INDEX 索引名
ON 表名 (索引列名);
创建组合索引的基本语法如下。
CREATE INDEX 索引名
ON 表名 (索引列名1, 索引列名2, ..., 索引列名N);
索引列名尽量为经常使用
WHERE
子句条件筛选的列,否则在性能上会得不偿失。
例题2:在学生表中,需要经常查询学生的手机号,则对学生表的 m o b i l e mobile mobile(手机号)字段添加单列索引,命令如下。
CREATE INDEX student_mobile_index
ON student (mobile);
提示:请逐行复制执行。
4.2 查询索引
索引创建完成后,可以用下面的命令,根据数据表来查询关联的索引。
.indices 数据表名
比如要查询学生表( s t u d e n t student student)上的所有索引,命令如下。
.indices student
查询结果如下图所示。
其中 sqlite_autoindex_student_1 是创建表时创建的隐式索引
同学们也可以查询所有数据表的索引列表,命令如下。
SELECT * FROM sqlite_master WHERE type = 'index';
4.3 Indexed By 子句
Indexed By 子句是对索引功能的应用,基本语法如下。
SELECT|DELETE|UPDATE 列名1, 列名2...
INDEXED BY (索引列名)
表名
WHERE (条件);
例题3:需要查询学生表中,手机号以 6 6 6 结尾的学生数据,命令如下。
SELECT * FROM student INDEXED BY student_mobile_index WHERE mobile GLOB '*6';
4.4 删除索引
如果发现索引作用不大,则可以删除索引,删除索引的基本语法如下。
DROP INDEX 索引名;
比如删除之前创建的 student_mobile_index
索引,命令如下。
DROP INDEX student_mobile_index;
4.5 索引技巧
同学们在使用索引时,需要注意以下几点:
- 索引不应该使用在较小的表上。
- 索引不应该使用在有频繁的大批量的更新或插入操作的表上。
- 索引不应该使用在含有大量的 NULL 值的列上。
- 索引不应该使用在频繁操作的列上。
提示:索引的目的是提高数据库性能,但错误运用索引反而会导致性能低下。
5 子查询
子查询通常出现在 WHERE
子句中,用来实现较为复杂的条件查询。
子查询可以与 SELECT、INSERT、UPDATE 、DELETE 语句和运算符一起使用。
子查询的基本语法如下。
SELECT 列名1, 列名2, ..., 列名N
FROM 表1, [ 表2 ]
WHERE 条件列名 OPERATOR
(SELECT 子列名1 [, 子列名2 ]
FROM 子表1 [, 子表2 ]
[WHERE])
例题4:需要查询有高等数学成绩的学生数据,查询的命令如下。
SELECT * FROM student WHERE code in (
SELECT code FROM achievement WHERE examination GLOB '*高等数学*'
);
查询结果如下图所示。
提示:请同学们逐行复制执行。
6 总结
通过本次博客学习,同学们需要独立编写 sqlite
触发器、视图、索引和子查询的命令,理解索引的概念和应用场景。
在下一篇博客中,将讲解 SQLite
中 SQL 函数和日期存储问题。