You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL Upsert非空约束异常排查(psycopg2+Supabase)

问题根源与解决方案

核心原因

  1. test_col_2存在NOT NULL约束:你提到无法将该列设为NULL,这直接证明了该列被配置为不允许空值。
  2. Upsert的INSERT分支触发约束:当你执行场景3的操作时,如果test_row_7这一行不存在于数据库中,Upsert会执行INSERT逻辑,但你没有提供test_col_2的值,导致该列被插入NULL,触发NOT NULL约束。
  3. 若确认test_row_7已存在,需检查SQL生成逻辑:你的代码理论上只会更新传入的列(test_col_1、test_col_3、test_col_4),不会修改test_col_2,这种情况下报错大概率是SQL语句生成错误,比如误将test_col_2加入更新列表。

验证步骤

先打印出生成的SQL语句排查问题,在cur.execute前添加代码:

print(f_s_sql_input)

场景3正确生成的SQL应该是:

INSERT INTO test_db (test_col_1, test_col_3, test_col_4) VALUES (%s, %s, %s) ON CONFLICT (test_col_1) DO UPDATE SET test_col_1 = excluded.test_col_1, test_col_3 = excluded.test_col_3, test_col_4 = excluded.test_col_4;

如果SQL与上述一致,说明问题就是目标行不存在,导致INSERT触发约束。

解决方案

方案1:仅更新已有行(不插入新行)

如果业务逻辑不需要插入新行,直接改用UPDATE语句:

# 调整SQL生成逻辑
f_s_col_names_update = [x+ " = %s" for x in f_l_col_names[1:]]
f_s_col_names_sql_update = ", ".join(f_s_col_names_update)
f_s_sql_input = f"UPDATE {f_s_sql_table_name} SET {f_s_col_names_sql_update} WHERE {f_l_col_names[0]} = %s;"

# 执行更新:传入要更新的列值 + 主键值
update_values = list(f_l_t_row_values[0][1:]) + [f_l_t_row_values[0][0]]
cur.execute(f_s_sql_input, update_values)

方案2:保留Upsert逻辑,确保INSERT分支满足约束

如果需要支持插入新行,必须在传入参数时包含test_col_2的值,或者修改表结构去掉test_col_2的NOT NULL约束(需符合业务规则)。

关于excluded关键字的说明

excluded是PostgreSQL Upsert中的虚拟表,存储你试图插入的行数据。当你未传入test_col_2时,excluded.test_col_2为NULL,但你的UPDATE逻辑并未修改test_col_2,所以只有INSERT分支会触发约束。


内容的提问来源于stack exchange,提问作者John Doe Python

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:06:06