Skip to content

CTE 与视图 ​

定义 ​

CTE(Common Table Expression,公共表表达式) 用 WITH 子句在单条 SQL 语句内定义临时命名结果集,供后续 SELECT / INSERT / UPDATE / DELETE 引用。视图(VIEW) 是持久化的「虚拟表」:保存一条 SELECT 定义,查询时动态展开,不单独存储数据(除非物化视图,SQLite 标准不支持)。

概念要点 ​

  • 作用域:普通 CTE 仅在当前语句内有效;执行完毕即消失。
  • 可读性:将复杂子查询拆成多步命名块,便于维护与复用逻辑。
  • 递归 CTE:WITH RECURSIVE 用「锚点成员 + 递归成员」迭代生成层级/图结构数据(组织树、路径、数列等)。
  • 视图 vs 表:视图不占独立数据页;INSERT/UPDATE/DELETE 能否写视图取决于列映射与规则(SQLite 对可更新视图有限制)。
  • 嵌套:CTE 可互相引用;视图可基于其它视图定义。

WITH 语法骨架 ​

sql
WITH [RECURSIVE] cte_name [(col1, col2, ...)] AS (
  -- 锚点或普通子查询
  SELECT ...
  [UNION ALL
  -- 递归成员(仅 RECURSIVE 时)
  SELECT ... FROM cte_name ...]
)
SELECT ... FROM cte_name ...;

递归 CTE 要点 ​

要点说明
必须 RECURSIVE递归引用自身时关键字不可省略
锚点 + 递归至少两个 SELECT,用 UNION ALL 连接
终止条件递归成员应随深度/条件收敛,避免无限循环
典型用途树形层级、传递闭包、日期序列、图遍历

语法 / 清单表 ​

操作语法
普通 CTEWITH name AS (SELECT ...) SELECT ...
多 CTEWITH a AS (...), b AS (...) SELECT ...
递归 CTEWITH RECURSIVE name AS (anchor UNION ALL recursive) SELECT ...
创建视图CREATE [TEMP] VIEW name [(cols)] AS select_stmt
替换视图CREATE VIEW name AS ... 需先 DROP;或用 DROP VIEW IF EXISTS 后重建
删除视图DROP VIEW [IF EXISTS] name
查看定义SELECT sql FROM sqlite_master WHERE type='view'

示例 ​

普通 CTE:按部门汇总后再过滤 ​

sql
WITH dept_stats AS (
  SELECT dept_id,
         COUNT(*) AS cnt,
         AVG(salary) AS avg_sal
  FROM employees
  GROUP BY dept_id
)
SELECT d.name, s.cnt, s.avg_sal
FROM departments d
JOIN dept_stats s ON d.id = s.dept_id
WHERE s.cnt >= 5;

递归 CTE:组织树层级 ​

sql
WITH RECURSIVE org_tree AS (
  -- 锚点:根节点(无上级)
  SELECT id, name, manager_id, 0 AS depth
  FROM employees
  WHERE manager_id IS NULL

  UNION ALL

  -- 递归:逐层向下找下属
  SELECT e.id, e.name, e.manager_id, t.depth + 1
  FROM employees e
  JOIN org_tree t ON e.manager_id = t.id
  WHERE t.depth < 10  -- 防止异常环导致无限递归
)
SELECT * FROM org_tree ORDER BY depth, id;

创建与使用视图 ​

sql
-- 创建:封装常用联表查询
CREATE VIEW active_users AS
SELECT u.id, u.name, u.email
FROM users u
WHERE u.deleted = 0;

-- 查询视图与查表语法相同
SELECT * FROM active_users WHERE name LIKE '张%';

-- 删除
DROP VIEW IF EXISTS active_users;

CTE 与视图组合 ​

sql
-- 视图持久化「活跃订单」定义
CREATE VIEW v_open_orders AS
SELECT o.id, o.user_id, o.total
FROM orders o
WHERE o.status = 'open';

-- 语句内 CTE 再做聚合
WITH monthly AS (
  SELECT strftime('%Y-%m', created_at) AS ym,
         SUM(total) AS revenue
  FROM v_open_orders
  GROUP BY ym
)
SELECT * FROM monthly ORDER BY ym;

易错点与交叉引用 ​

问题说明
忘记 RECURSIVE自引用 CTE 未加关键字会报错
递归无终止数据环或条件缺失导致达到递归深度上限
把 CTE 当持久对象CTE 不写入 schema;需复用请用视图或表
视图可更新性复杂 JOIN/聚合视图通常不可直接 INSERT/UPDATE
同名冲突同一语句内外层 CTE 名勿与表名混淆

相关章节:SELECT · JOIN · 分组与 HAVING · 事务

SQLite 官方参考 ​