# 42830 — 无效外键（invalid_foreign_key）

> PostgreSQL SQLSTATE 42830（无效外键，invalid_foreign_key）的源码证据、诊断与处理参考。
---

# 42830 — 无效外键（invalid_foreign_key）

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

`42830` 是 **invalid_foreign_key（无效外键）**：外键定义在被引用列上找不到合格唯一键。本案例的父表整数列没有唯一约束。

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

| 字段 | 值 |
| --- | --- |
| SQLSTATE | `42830` |
| 条件名 | `invalid_foreign_key` |
| 状态 | `有效` |
| 已知存在于 | `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_INVALID_FOREIGN_KEY` |
| 别名 | `—` |

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

## 含义 {#meaning}

创建时先检查父键，尚未插入子行。固定主报文为 `there is no unique constraint matching given keys for referenced table "%s"`。普通 FK 的被引用列集合可以匹配物理顺序不同但合格的唯一索引；源码匹配器会拒绝被引用列重复，并要求列数正确、唯一、有效且没有部分谓词或索引表达式。若匹配到可延迟的唯一/主键索引，则进入仅源码确认的 `55000` 分支。这是定义时错误，不同于 `23503`；自动提交 ALTER 失败后为 `IDLE`。

## 诊断 {#diagnosis}

将被引用列集合与 `pg_constraint`、`pg_index` 对照。检查重复引用、列数、唯一/主键属性、有效性、部分谓词和表达式；普通路径不要求物理索引顺序与 FK 列表相同。还要检查 `indimmediate`：匹配但可延迟的键会报 `55000`，不是本案例的 `42830`。类型相同本身不能使键符合要求。

## 处理 {#response}

在被引用列集合上添加或使用有意且不可延迟的唯一键，再创建 FK。核对父表键的业务含义及 NULL/MATCH 语义；过宽唯一约束可能改变可接受数据。不要为了匹配 FK 书写顺序而重排本来合格的索引，也不要把部分或表达式索引当作合格键。案例添加 `UNIQUE (id)` 后创建 FK。显式事务中被拒绝的 `ALTER TABLE` 会使事务进入 `INERROR`，应先回滚或回到合适的 savepoint 再重试；本案例的自动提交路径回到 `IDLE`。

## 实测诊断 {#messages}

选定 `tablecmds.c` 组是 `ERROR`，主报文为 `there is no unique constraint matching given keys for referenced table "%s"`，没有 DETAIL/HINT。同一匹配器还有仅源码确认的 `55000`（`object_not_in_prerequisite_state`）变体：当唯一键本来匹配但可延迟时为 `cannot use a deferrable unique constraint for referenced table "%s"`。

## 代表案例 {#case}

注册表创建父子表，先尝试 FK，再添加父唯一键、创建有效 FK 并统计。

<!-- BEGIN SQLSTATE SNIPPET: fk_missing_unique_key -->

```sql
CREATE TABLE syntax_schema.fk_parent (id integer);
CREATE TABLE syntax_schema.fk_child (parent_id integer);
ALTER TABLE syntax_schema.fk_child ADD CONSTRAINT fk_bad FOREIGN KEY (parent_id) REFERENCES syntax_schema.fk_parent (id);
ALTER TABLE syntax_schema.fk_parent ADD CONSTRAINT fk_parent_id_key UNIQUE (id);
ALTER TABLE syntax_schema.fk_child ADD CONSTRAINT fk_good FOREIGN KEY (parent_id) REFERENCES syntax_schema.fk_parent (id);
SELECT count(*) FROM pg_constraint c JOIN pg_namespace n ON n.oid = c.connamespace WHERE n.nspname = 'syntax_schema_name' AND c.conname = 'fk_good' AND c.contype = 'f';
```

<!-- END SQLSTATE SNIPPET -->

选定的 18.6 与 10.21 运行均通过 SQLSTATE、严重级别、状态/恢复、修复、清理和一次性实例停止断言。详见 [`案例 JSON`](../../data/cases/42830.json) 与 [`作者证据`](../../data/evidence/42830.json)；私有清单和注册表哈希也记录在其中。

## 版本 {#versions}

锁定目录从 7.4 存在边界起包含该条件并列出相关快照。选定自然案例已在 PostgreSQL 18.6 与 10.21 通过；这是有界观察，不能推断所有中间版本或所有源码分支。

## 相关 {#related}

- [`23503`](../23503/)
- [`23514`](../23514/)

## 来源 {#sources}

- `src.errcodes.REL_18_6` — fixed definition at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt#L1-L1)).
- `src.invalid-fk.18.6` — `src/backend/commands/tablecmds.c` lines 13639–13642 at `724edf9bde9d356724ad384a2e196edc3c9f80f7`; blob SHA-256 `422dc8e833df4940755973c757e338295822ba3e4c7266c40669f49f96eb15a9` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/tablecmds.c#L13639-L13642)).
- `src.invalid-fk.10.23` — `src/backend/commands/tablecmds.c` lines 8133–8136 at `02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4`; blob SHA-256 `6de441c88496c6cf57a836898388085ec08bf69afd70d07acdafd6089b9b5f8c` ([source](https://github.com/postgres/postgres/blob/02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4/src/backend/commands/tablecmds.c#L8133-L8136)).
- `src.invalid-fk-guards.18.6` — `transformFkeyCheckAttrs` 完整源码为 `src/backend/commands/tablecmds.c` lines 13505–13642，commit `724edf9bde9d356724ad384a2e196edc3c9f80f7`；blob SHA-256 `422dc8e833df4940755973c757e338295822ba3e4c7266c40669f49f96eb15a9` ([source](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/tablecmds.c#L13505-L13642)).
- `src.invalid-fk-guards.10.23` — `transformFkeyCheckAttrs` 完整源码为 `src/backend/commands/tablecmds.c` lines 8002–8136，commit `02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4`；blob SHA-256 `6de441c88496c6cf57a836898388085ec08bf69afd70d07acdafd6089b9b5f8c` ([source](https://github.com/postgres/postgres/blob/02991e79f8f58bc208f05dcc8af0c62dbe0a6ea4/src/backend/commands/tablecmds.c#L8002-L8136)).
- `src.calls.REL_18_6` / `src.calls.REL_10_23` — fixed call scans, SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf` / `00d16d3eb01b71ccf1b245c8f3102f9d0ec9f36fb02777b8dd1b99fcb263040c`.
- `manifest.42830` / `snippet-registry.42830` — hashes are recorded in `evidence/42830.json` and each runtime record.
