PostgreSQL使用nextval序列作为UPDATE WHERE条件不生效问题求助
问题根源
nextval()函数每次调用都会主动推进序列的值,且写在UPDATE的WHERE条件中时,每扫描表中的一行就会执行一次,而非全局只计算一次。假设你的表中有9行数据,执行UPDATE时会连续调用9次nextval(),序列值连续步进9次,自然会出现随机匹配到多行、或者完全匹配不到目标行的异常。- 你的实现逻辑存在冗余:不需要单独写UPDATE语句做覆盖,用UPSERT(插入时冲突则更新)的逻辑完全可以同时处理首次插入和循环覆盖两个场景。
修复步骤
- 先给id列添加主键约束,用于判断插入冲突:
ALTER TABLE test_seq ADD PRIMARY KEY (id);
- 废弃原来的UPDATE写入逻辑,改用如下INSERT语句写入新数据,自动实现前25次插入新行、25次后循环覆盖旧行的效果:
-- 要写入新的raw_data时执行这条语句即可 INSERT INTO test_seq (id, raw_data) VALUES (DEFAULT, '你要写入的新数据内容') ON CONFLICT (id) DO UPDATE SET raw_data = EXCLUDED.raw_data;
原理解释
- 插入时使用
DEFAULT关键字会自动调用id列的默认值逻辑,通过序列生成下一个cd_x格式的ID,全程只调用一次nextval(),序列只会步进一次,不会出现乱跳的问题。 ON CONFLICT (id) DO UPDATE逻辑会在ID重复(序列循环到已经用过的ID)时,直接覆盖对应ID行的raw_data内容,完全符合你循环覆盖保留最多25条记录的需求。
如果需要追溯数据写入时间,还可以额外加一个更新时间字段:
-- 加字段 ALTER TABLE test_seq ADD COLUMN update_time TIMESTAMP DEFAULT NOW(); -- 同步修改UPSERT语句,更新时刷新时间 INSERT INTO test_seq (id, raw_data) VALUES (DEFAULT, '你要写入的新数据内容') ON CONFLICT (id) DO UPDATE SET raw_data = EXCLUDED.raw_data, update_time = NOW();
内容的提问来源于stack exchange,提问作者LaZoR_Bear
相关产品推荐
相关产品推荐

