我正在使用Postgres 9.5并在这里看到一些有线的东西.
我有一个cron作业运行5分钟,触发一个sql语句,如果不存在则添加一个记录列表.
INSERT INTO soMetable (customer,balance) VALUES (:customer,:balance) ON CONFLICT (customer) DO NOTHING
soMetable.customer是主键(文本)
可行的结构是:
id:连续
客户:文字
平衡:bigint
现在似乎每次这个作业运行时,id字段都会以静默方式递增1.所以下次,我真的添加一个字段,它比我上一个值高出数千个数字.我认为这个查询检查冲突,如果是这样,什么也不做,但目前似乎它试图插入记录,增加id然后停止.
有什么建议?
解决方法
这对你来说很奇怪的原因是你正在考虑作为插入操作的一部分计数器的增量,因此“DO NOTHING”应该意味着“不要增加任何东西”.你想象的是:
>检查要根据约束插入的值
>如果检测到重复,则中止
>增量序列
>插入数据
但事实上,增量必须在尝试插入之前发生. Postgres中的SERIAL列实现为DEFAULT,它在绑定的SEQUENCE上执行nextval()函数.在DBMS可以对数据执行任何操作之前,它必须有一组完整的列,因此操作顺序如下:
>解析默认值,包括递增序列
>检查要根据约束插入的值
>如果检测到重复,则中止
>插入数据
如果重复键位于自动增量字段本身中,则可以直观地看到:
CREATE TABLE foo ( id SERIAL NOT NULL PRIMARY KEY,bar text ); -- Insert row 1 INSERT INTO foo ( bar ) VALUES ( 'test' ); -- Reset the sequence SELECT setval(pg_get_serial_sequence('foo','id'),true); -- Attempt to insert row 1 again INSERT INTO foo ( bar ) VALUES ( 'test 2' ) ON CONFLICT (id) DO NOTHING;
很明显,这不能知道是否存在冲突而不增加序列,因此“无所事事”必须在增量之后出现.