SQLite视图是保存的SELECT查询,创建时必须带合法SELECT且不能有顶层ORDER BY/LIMIT;删除需用DROP VIEW IF EXISTS;不支持ALTER VIEW,只能先删后建;仅简单单表投影视图可更新,其余均为只读。

SQLite 中创建和删除视图非常直接,但有几个关键点不注意就会报错或行为不符合预期——比如用 CREATE VIEW 时没加 IF NOT EXISTS,或者误以为视图能像表一样随意更新。
CREATE VIEW 语句必须带 SELECT,且不能有 ORDER BY / LIMIT(除非在子查询里)
SQLite 视图本质是保存的查询语句,不是真实表。所以 CREATE VIEW 后面必须跟一个合法的 SELECT,而且这个 SELECT 本身不能包含顶层的 ORDER BY 或 LIMIT ——否则会报错 near "ORDER": syntax error。
常见错误写法:
CREATE VIEW top_users AS SELECT * FROM users ORDER BY score DESC LIMIT 5;
正确做法是把排序和限制包进子查询:
CREATE VIEW top_users AS SELECT * FROM (SELECT * FROM users ORDER BY score DESC LIMIT 5);
- 视图定义里不能有
WITH子句(SQLite 3.34+ 支持,但需确认版本) - 字段别名必须明确,避免
SELECT *在基表结构变更后导致视图失效或列顺序错乱 - 如果基表不存在,
CREATE VIEW仍会成功,但首次查询时才报错no such table: xxx
DROP VIEW 必须用 IF EXISTS,否则表不存在就报错
DROP VIEW 默认是“硬删除”,如果视图不存在,直接报错 no such view: xxx。生产环境脚本里几乎 always 要加 IF EXISTS:
DROP VIEW IF EXISTS user_summary;
不加 IF EXISTS 的后果:
- 在迁移脚本中执行两次会中断后续 SQL
- 无法安全用于初始化逻辑(比如“先删再建”模式)
- 和
CREATE VIEW IF NOT EXISTS不对称,容易漏掉
ALTER VIEW 不支持,只能 DROP + CREATE
SQLite 完全没有 ALTER VIEW 语法。想改视图逻辑,必须先删后建:
DROP VIEW IF EXISTS user_info; CREATE VIEW user_info AS SELECT id, name, email FROM users WHERE active = 1;
注意点:
- 视图被其他视图或触发器引用时,
DROP VIEW不会警告,但后续查询会失败 - 临时视图(
CREATE TEMP VIEW)只在当前连接有效,关掉连接自动消失,不用手动删 - 如果视图定义依赖多个表,而其中某个表被
DROP TABLE,视图不会自动失效,首次查询才暴露问题
可更新视图的限制极严,别默认它能 INSERT/UPDATE
只有最简单的单表投影视图才支持写操作。例如:
CREATE VIEW simple_users AS SELECT id, name FROM users;
这个视图允许 UPDATE simple_users SET name = 'new' WHERE id = 1;,但以下任意一条都会让它变成只读:
- 含
JOIN、GROUP BY、DISTINCT - 含聚合函数(
COUNT()、SUM()等) - 含子查询或
UNION - SELECT 列里用了表达式(如
name || '_v2')
试图更新不可更新视图会报错 attempt to change a readonly database 或更具体的 not authorized ——这不是权限问题,是语法限制。
真正容易被忽略的是:视图不存数据,也不建索引,所有查询都实时展开底层 SELECT。哪怕只是 SELECT * FROM big_view WHERE id = ?,如果底层查的是 JOIN + GROUP BY,性能可能比直接查原表还差。

















