# 42P01 — undefined_table：未定义的表或关系

> 当引用的关系无法解析时，PostgreSQL 会报告 SQLSTATE 42P01。应检查模式限定、search_path、标识符引用和迁移，再决定是否创建或重命名对象。
---

## 速览 {#at-a-glance}

`42P01` 是 PostgreSQL 类别 42 `syntax_error_or_access_rule_violation` 中的 `undefined_table` 条件。这个名称沿袭已久；无法解析的引用可以是表、视图、物化视图、外部表或其他关系名称。

普通诊断是未限定引用的 `relation "%s" does not exist`，或限定引用的 `relation "%s.%s" does not exist`。解析器在查询执行前报告 SQLSTATE；自动提交连接不会因为这个查询错误留下失败事务。

代表性案例查询不存在的模式限定关系，再创建有效关系并读取它。PostgreSQL 18.6 和隔离的 PostgreSQL 10.21 目标均返回 `42P01`，连接保持 `IDLE`，修正后的查询成功。run ID 和断言见[公开证据 JSON](../../data/evidence/42p01.json)。

<!-- BEGIN SQLSTATE FACTS: generated by scripts/generate.py; do not edit -->

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `42P01` |
| 条件名 | `undefined_table` |
| 状态 | `有效` |
| 已知存在于 | `7.4` |
| 锁定快照 | `9.0.23, 9.1.24, 9.2.24, 9.3.25, 9.4.26, 9.5.25, 9.6.24, 10.23, 11.22, 12.22, 13.23, 14.24, 15.19, 16.15, 17.11, 18.6, 19beta3` |
| 宏 | `ERRCODE_UNDEFINED_TABLE` |
| 别名 | `—` |

<!-- source facts: data/errcodes/42P01.json -->
<!-- END SQLSTATE FACTS -->

## 含义与触发路径 {#meaning}

解析阶段会根据当前命名空间和 `search_path` 解析每个关系。如果限定名称不存在，`parse_relation.c` 产生两部分名称报文；如果未限定名称不存在，则产生一部分名称报文。拼写错误、迁移尚未执行、连接了错误数据库、`search_path` 不同，或者带引号标识符大小写不一致，都可能产生这个 SQLSTATE。

这是名称解析错误，不等于物理表一定被删除。关系可能存在于另一个模式或数据库中，角色也可能缺少查看或使用它所需的权限。反过来，按猜测的名称创建表会掩盖部署或引用错误。

解析器还会在某些无效 `FROM` 项引用和 CTE 前向引用中使用 `42P01`，但 detail 或 hint 可能不同。应结合完整报文和上下文，将这些形式与缺少关系区分开。

## 报文与诊断 {#messages}

runner 的操作先限定模式查询，再查询修正后的关系。隔离 harness 提供临时模式；查询形状如下：

<!-- BEGIN SQLSTATE SNIPPET: missing_relation -->
```sql
SELECT * FROM does_not_exist;
CREATE TABLE exists(id integer PRIMARY KEY);
SELECT count(*) FROM exists;
```
<!-- END SQLSTATE SNIPPET -->

PostgreSQL 18.6 返回：

```text
SQLSTATE: 42P01
severity: ERROR
message_primary: relation "c42p01_missing_relation.does_not_exist" does not exist
source: parse_relation.c / parserOpenTable / line 1480
```

PG10 目标返回相同的主报文，对应源码行号为 1159。限定形式会在报文中保留模式和关系名称。未限定引用使用固定源码模板 `relation "%s" does not exist`；CTE 前向引用或无效 `FROM` 引用可能附带 detail 或 hint。

## 诊断 {#diagnosis}

记录 SQLSTATE、主报文、detail、hint、语句位置、当前数据库、角色和 `search_path`。检查应用使用的准确拼写与引用方式。通过有权限的管理连接查询 `pg_class`/`pg_namespace` 或使用 `to_regclass()`，确认关系实际存在的位置。

对照已部署迁移版本、连接数据库和模式。连接池中的 session 可能带有不同于建表连接的 `search_path`。如果对象预期是临时对象，应确认查询仍在创建它的同一个 session 中执行。

代表性错误发生在自动提交下，连接保持 `IDLE`；修正后的查询返回 count `0` 并仍为 `IDLE`。如果缺少关系的引用发生在显式事务中，事务仍可能进入 `INERROR`，因此应记录实际状态，不要假定所有 `42P01` 都不会影响周围工作。

## 处理与修复 {#response}

按部署和应用配置修复名称解析原因：

- 明确选择目标模式，或为 session 设置并验证 `search_path`。
- 在提供查询前于正确数据库执行缺少的迁移。
- 对大小写敏感的标识符保留准确的双引号；检查依赖后再按统一约定重命名。
- 只有在缺少对象是预期分支时才使用 `to_regclass()` 等预检；意外部署失败不应静默创建替代关系。

修正关系后重新执行原查询，并验证返回值和事务状态。成功执行 `CREATE TABLE` 或打开新连接，都不能证明所有应用 session 解析到同一个对象。

## 版本与边界 {#versions}

目录在 PostgreSQL 7.4 的锁定定义中已观察到 `42P01`，并持续到 8.4.22 的 pre-9.0 定义；随后在列出的所有正式快照直到 PostgreSQL 18.6 以及 PostgreSQL 19 Beta 3 预览中存在。这是 definition_only 的存在边界，不是确切实现引入版本或运行时使用断言。扫描范围内没有记录该条件的定义变化。

缺少关系案例在 PostgreSQL 18.6 和 10.21 上均通过。源码行号和解析器 hint 会因版本及引用形式变化。本页覆盖模式限定的缺少关系和有效后续查询，不覆盖所有使用 `42P01` 的命名空间或访问规则路径。

## 相关 {#related}

[`42P02` — `undefined_parameter`](../42p02/) 处理缺少查询参数。[`3F000` — `invalid_schema_name`](../3f000/) 处理无效模式名称。[`42501` — `insufficient_privilege`](../42501/) 是名称解析之后的访问失败。[`57014` — `query_canceled`](../57014/) 可能中断修复查询，但原因不同。

## 来源 {#sources}

结构化证据记录在[公开证据 JSON](../../data/evidence/42p01.json)中。源码记录固定到 PostgreSQL commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`；运行记录保留两个目标 ID 和结构化观察。

- `src.errcodes.18.6` — [`errcodes.txt`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L371-L376)
- `src.parse-relation.18.6` — [`parse_relation.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/parser/parse_relation.c#L1473-L1501)
- `src.namespace.18.6` — [`namespace.c`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/catalog/namespace.c#L626-L640)
- `doc.ddl.18.6` — [模式](https://www.postgresql.org/docs/18/ddl-schemas.html)
- Runtime：latest 与 pg10 均为 `42P01-registry-final-20260909`，结构化观察见[公开证据 JSON](../../data/evidence/42p01.json)
