# 23502 — 非空约束冲突（not_null_violation）

> PostgreSQL SQLSTATE 23502：非空约束冲突的来源与诊断参考。
---

# 23502 — 非空约束冲突

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

`23502` 表示 NULL 到达了 NOT NULL 规则。本案例识别出列 `label` 和关系 `items`；18.6 与 10.21 的英文主报文关系措辞略有差异，但 SQLSTATE 和结构化对象一致。

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

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

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

## 含义 {#meaning}

执行器检查元组的 NOT NULL 属性并带出列、关系及可选的失败行 DETAIL。模式校验和域的 NOT NULL 校验也会使用该码，但源码模板不同；域 CHECK 失败属于 `23514` 路径。默认值、显式值、生成表达式或模式变更的选择取决于 NULL 的来源。

## 诊断 {#diagnosis}

保存 `column_name`、`table_name` 和 DETAIL。选定案例中，18.6 主报文包含 `of relation "items"`，10.21 则省略该短语；应使用结构化字段，不要匹配完整英文报文。沿参数、类型转换、生成列、触发器和 `INSERT ... SELECT` 追踪值。自动提交案例错误后仍为 `IDLE`；外层显式事务需要回滚或处理器。

## 处理 {#response}

填入合法值、明确采用默认值，或在检查既有数据和下游读取方后调整约束。不要为了掩盖缺失值而删除 NOT NULL，或把它换成更弱的 CHECK；NULL 能否出现必须是有意的数据契约。新增 NOT NULL 的迁移要先校验既有数据，保持模式变更事务边界显式。

## 实测诊断 {#messages}

`18.6 (Homebrew) / latest`：SQLSTATE `23502`；primary `null value in column "label" of relation "items" violates not-null constraint`；DETAIL `Failing row contains (2, null).`；status_after_error `IDLE`。
`10.21 (Debian 10.21-1.pgdg90+1) / pg10`：SQLSTATE `23502`；primary `null value in column "label" violates not-null constraint`；DETAIL `Failing row contains (2, null).`；status_after_error `IDLE`。

## 代表案例 {#case}

运行器从 `verify/cases/23502/snippets.json`（SHA-256 `f701e32a0e9214d6c88deabcda99981c288cae0f176d1dcaf383863c3942f8e0`）读取下列片段，并为临时 schema 替换表名；完整 setup、断言与清理见 [案例导出](../../data/cases/23502.json)。

<!-- BEGIN SQLSTATE SNIPPET: not_null_insert -->
```sql
-- create
CREATE TABLE items(id integer PRIMARY KEY, label text NOT NULL);
-- seed
INSERT INTO items VALUES (1, 'seed');
-- trigger
INSERT INTO items VALUES (2, NULL);
-- repair
INSERT INTO items VALUES (2, 'valid');
-- verify
SELECT id, label FROM items ORDER BY id;
```
<!-- END SQLSTATE SNIPPET -->

本案例对应的 SQLSTATE、诊断、事务状态和修复断言均来自上述共享 registry；[结构化证据](../../data/evidence/23502.json) · [案例导出](../../data/cases/23502.json)。

作者证据 ID：`identity`, `dml-path`, `schema-path`, `runtime`。选定运行记录：`runtime.23502-batch1-latest-20260909.latest`, `runtime.23502-batch1-pg10-20260909.pg10`。

## 版本与边界 {#versions}

锁定目录在 `7.4` 已观察到该条件，并在列出的正式快照中均存在。选定运行只覆盖 18.6 与 10.21 的普通 INSERT，不覆盖 ALTER TABLE 校验、域、分区或触发器生成 NULL。

## 相关 {#related}

对比 [23514 CHECK 冲突](../23514/)、[23503 外键冲突](../23503/) 和 [23505 唯一约束冲突](../23505/)。

## 来源 {#sources}

- [`src.errcodes.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/utils/errcodes.txt) (SHA-256 `6e8de346643ba84aa3c9c6a73360acfc7b2dfb89162c06c08ce9bf5bcd5bbcba`)
- `src.calls.REL_18_6` (SHA-256 `9ee8a0e81d8f0825c5c1ae45583439859a26e602bdd4ce2f2a62aa278867ccbf`)
- [`src.execMain.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/executor/execMain.c#L2213-L2219) (SHA-256 `33b97337fa23a649c5e7a092e1bd405a54e8503529236c62c9d5bb93a1774a8d`)
- [`src.tablecmds.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/tablecmds.c#L6465-L6490) (SHA-256 `422dc8e833df4940755973c757e338295822ba3e4c7266c40669f49f96eb15a9`)
- [`src.typecmds.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/src/backend/commands/typecmds.c#L3199-L3204) (SHA-256 `60d1e9754646e100f6b74aa367ad8c2c52386c400df721707423d329209c47eb`)
- [`doc.ddl-constraints.18.6`](https://github.com/postgres/postgres/blob/724edf9bde9d356724ad384a2e196edc3c9f80f7/doc/src/sgml/ddl.sgml) (SHA-256 `ce1919d9236f2e71672660e1a347146472e966e4d19b77fde5ae345dd1db6ec7`) · [官方文档](https://www.postgresql.org/docs/18/ddl-constraints.html)
