SQLite06-常用对象
1、视图(View)
(1)概念
- 虚拟表定义
- 视图是基于预定义
SELECT 查询的虚拟表,不存储实际数据。
- 数据动态生成:每次查询视图时实时执行底层 SQL 语句。
- 核心用途
- 简化复杂查询:封装多表连接或聚合操作。
- 数据安全:限制用户访问敏感字段(如隐藏薪资列)。
- 逻辑抽象:为应用层提供统一数据接口。
- 只读限制
- 不支持直接修改:无法在视图上执行
INSERT/UPDATE/DELETE。
- 替代方案:通过
INSTEAD OF 触发器间接实现数据更新(需自定义逻辑)。
(2)视图创建
-- 基础语法
CREATE VIEW [IF NOT EXISTS] 视图名称 AS
SELECT 列1, 列2, ...
FROM 表名
[WHERE 条件]
[GROUP BY 分组]
[HAVING 过滤条件];
-- 创建视图:客户订单视图
CREATE VIEW customer_orders AS
SELECT customers.name, orders.product, orders.order_date
FROM customers
JOIN orders ON customers.id = orders.customer_id;
-- 创建视图:公开员工信息(隐藏薪资)
CREATE VIEW employee_public AS
SELECT id, name, department FROM employees;
(3)视图查询
-- 与查询普通表语法相同
SELECT * FROM 视图名称 [WHERE 条件];
-- 筛选 2023 年后的订单
SELECT * FROM customer_orders
WHERE order_date > '2023-01-01';
(4)视图删改
-- 删除视图
DROP VIEW IF EXISTS 视图名称;
-- 更新视图(需删除后重建)
DROP VIEW IF EXISTS employee_public;
CREATE VIEW employee_public AS
SELECT id, name, department, hire_date FROM employees; -- 新增入职日期列
(5)综合案例
- 场景:整合
products(产品表)、sales(销售表)生成月度销售汇总视图。
-- 创建视图:月度销售汇总
CREATE VIEW monthly_sales_report AS
SELECT
strftime('%Y-%m', sale_date) AS month, -- 按月分组
products.name AS product_name,
SUM(sales.quantity) AS total_quantity,
SUM(sales.quantity * products.price) AS total_revenue
FROM sales
JOIN products ON sales.product_id = products.id
GROUP BY month, product_name;
-- 获取 2024 年销售额最高的产品
SELECT product_name, total_revenue
FROM monthly_sales_report
WHERE month LIKE '2024-%'
ORDER BY total_revenue DESC
LIMIT 5;
(6)注意事项
-- 错误示例:禁止通过视图插入数据
INSERT INTO customer_orders VALUES ('Alice', 'Laptop', '2025-07-15'); -- 报错!
- 性能优化:避免嵌套多层视图(如
VIEW_A 依赖 VIEW_B),可能导致查询效率下降。
2、索引(Index)
(1)概念
- 核心定义
- 索引是数据库中的特殊数据结构,类似于书籍的目录。它通过建立字段值与数据位置的映射关系,避免全表扫描,显著提升查询效率。
- 类比:通过字典拼音目录查字,无需逐页翻阅。
- 核心价值
- ✅ 加速查询:对
WHERE、JOIN、ORDER BY 等操作优化明显。
- ❌ 副作用:增加存储空间,降低
INSERT/UPDATE/DELETE 速度(需同步维护索引)
(2)索引创建
-- 基础语法
CREATE INDEX [IF NOT EXISTS] 索引名
ON 表名(列名);
-- 示例:为 employees 表的 salary 列创建索引
CREATE INDEX idx_salary ON employees(salary);
-- 强制列值的唯一性
CREATE UNIQUE INDEX [IF NOT EXISTS] 索引名
ON 表名(列名);
-- 示例:防止 users 表的 email 重复
CREATE UNIQUE INDEX uq_email ON users(email);
-- 基于多列的联合查询优化
CREATE INDEX 索引名
ON 表名(列1, 列2);
-- 示例:优化 orders 表的 user_id 和 status 联合查询
CREATE INDEX idx_user_status ON orders(user_id, status);
(3)索引查看
-- 查看当前数据库所有索引
SELECT name, sql FROM sqlite_master WHERE type = 'index';
-- 查看特定表索引
.indices 表名 -- SQLite 命令行工具专用语法
-- 显示索引的创建语句
.schema 索引名
(4)索引删除
-- 基础语法
DROP INDEX [IF EXISTS] 索引名;
-- 示例:删除无效索引
DROP INDEX IF EXISTS idx_old;
(5)隐式索引
- 自动创建场景:主键(
PRIMARY KEY)和唯一约束(UNIQUE)会自动生成唯一索引,例如:
CREATE TABLE products (
id INTEGER PRIMARY KEY, -- 自动创建隐式索引
sku TEXT UNIQUE -- 自动创建隐式索引
);
(6)注意事项
- 性能权衡
- 适用场景:频繁的
WHERE、JOIN 或 ORDER BY 操作列
- 避免场景:小表(数据量 < 1000行)、高频写入列(降低 INSERT/UPDATE 速度)
- 组合索引优化
- 列顺序原则:将高频查询条件列放在左侧
- 示例:
WHERE a=1 AND b=2 优先使用 (a,b) 而非 (b,a)
- 索引维护建议
- 定期重建:数据频繁修改后使用
REINDEX 索引名 优化性能
- 命名规范:建议使用
idx_表名_列名 格式提升可读性
3、触发器(Trigger)
(1)概念
- 在指定数据库事件(增/删/改)发生时自动执行预设操作,常用于:
- 数据校验:拦截非法值(如负数的库存)
- 级联更新:自动同步关联表数据(如订单表删除时清理明细表)
- 审计追踪:记录关键操作日志(如用户表修改时备份旧数据)
- 业务计算:实时更新统计字段(如订单总额变化时刷新客户总消费)
(2)类型详解
| 类型 |
语法关键字 |
执行时机 |
| BEFORE 触发器 |
BEFORE INSERT/UPDATE/DELETE |
在操作生效前执行,可修改或取消操作 |
| AFTER 触发器 |
AFTER INSERT/UPDATE/DELETE |
在操作生效后执行,适合日志记录 |
| 类型 |
语法关键字 |
说明 |
| 行级触发器 (ROW) |
FOR EACH ROW |
默认类型,每影响一行数据触发一次 |
| 语句级触发器 |
❌ 不支持 |
SQLite 仅支持行级触发器 |
- 重要限制:SQLite 不支持
INSTEAD OF 触发器(常用于视图更新)
(3)核心语法
-- 基础语法
CREATE TRIGGER [IF NOT EXISTS] 触发器名
[BEFORE | AFTER] [INSERT | UPDATE | DELETE] ON 表名
FOR EACH ROW -- SQLite 仅支持行级触发器
[WHEN 条件]
BEGIN
-- 触发动作(SQL 语句)
END;
-- 删除触发器
DROP TRIGGER IF EXISTS 触发器名;
- 关键特性:
- 行级触发:每行数据变更都会激活触发器(
FOR EACH ROW 必选)
- 临时表访问:
NEW.列名 → 获取 插入/更新后 的值
OLD.列名 → 获取 更新前/删除前 的值
- 异常处理:用
RAISE() 抛出错误(如 RAISE(ABORT, '错误消息'))
(4)案例演示
-- 禁止插入未来入职日期的员工
CREATE TRIGGER validate_hire_date
BEFORE INSERT ON employees
FOR EACH ROW
WHEN NEW.hire_date > date('now')
BEGIN
RAISE(ABORT, '入职日期不能是未来时间');
END;
- 效果:插入
hire_date = '2025-12-31' 时触发报错。
- ✅ 案例 2:自动审计日志
-- 记录薪资变更历史
CREATE TRIGGER log_salary_changes
AFTER UPDATE ON salaries
FOR EACH ROW
BEGIN
INSERT INTO salary_audit(emp_id, old_salary, new_salary, change_time)
VALUES (OLD.emp_id, OLD.amount, NEW.amount, datetime('now'));
END;
- 效果:每次薪资更新时自动记录变更前后的值。
- ✅ 案例 3:级联删除关联数据
-- 删除员工时同步删除相关记录
CREATE TRIGGER cascade_employee_delete
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
DELETE FROM salaries WHERE emp_id = OLD.id;
DELETE FROM titles WHERE emp_id = OLD.id;
END;
- 效果:删除员工后自动清理薪资和职位表。
- ✅ 案例 4:自动计算字段
-- 更新库存金额(数量 × 单价)
CREATE TRIGGER update_inventory_value
AFTER UPDATE OF quantity, price ON inventory
FOR EACH ROW
BEGIN
UPDATE inventory
SET total_value = NEW.quantity * NEW.price
WHERE id = NEW.id;
END;
(5)注意事项
- 只读性限制:SQLite 不支持通过触发器修改
NEW 值(不同于 MySQL)。
- 性能影响:避免在频繁更新的表上创建复杂触发器,可能拖慢写入速度。
- 递归触发:确保触发器逻辑不会循环调用自身(如
A 触发器 → 更新表 → 激活 A 触发器)。
- 临时表作用域:
OLD/NEW 仅在行级触发器中有效,语句级触发器不可用。
4、临时表(Temporary)
(1)概念
- SQLite中的临时表是一种特殊的表,用于临时存储中间数据,其生命周期与数据库连接绑定,连接断开后自动删除,无需手动清理。
- 核心特点
- 自动删除:数据库连接断开后,临时表自动删除,无需手动执行
DROP TABLE命令
- 命名空间:在SQLite中,临时表会存储在
temp命名空间下,查看时显示为temp.tablename
- 会话隔离:临时表仅对创建它的连接可见,其他连接无法访问
- 作用意义
- 提高查询效率:对于复杂查询,将中间结果存储在临时表中,可以避免重复计算
- 减少主表压力:避免对主表进行多次扫描
- 简化逻辑:将复杂查询拆分为多个步骤,提高可读性
- 数据隔离:确保临时数据不会影响主表数据
(2)创建语法
CREATE TEMPORARY TABLE tablename (
dataname datatype
);
CREATE TEMPORARY TABLE temp_sales (
sale_id INTEGER PRIMARY KEY,
amount DECIMAL(10, 2)
);
-- 创建临时表
CREATE TEMPORARY TABLE temp_products (
product_id INTEGER PRIMARY KEY,
product_name TEXT,
price DECIMAL(10, 2)
);
-- 插入数据
INSERT INTO temp_products VALUES (1, 'Laptop', 999.99);
INSERT INTO temp_products VALUES (2, 'Smartphone', 599.99);
-- 查询临时表
SELECT * FROM temp_products;
-- 临时表在当前连接结束时自动删除,无需DROP
(3)使用场景
- 临时存储中间结果:在复杂查询中存储中间结果,避免重复计算
- 数据处理:处理大数据集时分步处理,减少内存压力
- 数据隔离:在会话中隔离临时数据,避免污染主表
(4)临时表 vs 常规表
| 特性 |
临时表 |
常规表 |
| 生命周期 |
仅当前连接存在 |
持久存储 |
| 作用域 |
仅创建它的连接可见 |
所有连接可见 |
| 删除方式 |
自动删除 |
需手动DROP |
| 存储位置 |
临时文件 |
数据库文件 |
(5)临时表 vs 子查询
- SQLite中也可以使用子查询作为临时表(派生表),例如:
SELECT * FROM (
SELECT product_id, price
FROM products
WHERE price > 500
) AS temp_table;
- 这种子查询方式创建的"临时表"仅在当前查询中有效,而
CREATE TEMPORARY TABLE创建的临时表可以在后续多个查询中重复使用。