关于这个答案,我遇到了一个无法解释的现象。
版本:
PostgreSQL 9.1.2在x86_64-unknown-linux-gnu上,由gcc-4.4.real(Debian 4.4.5-8)4.4.5编译,64位
测试环境:
CREATE TEMP TABLE t (
id integer
, txt text
, CONSTRAINT t_pkey PRIMARY KEY (id) DEFERRABLE INITIALLY IMMEDIATE
);
INSERT INTO t VALUES
(1, 'one')
, (2, 'two');
1) UPDATE
语句修改多行:
UPDATE t
SET id = t_old.id
FROM t t_old
WHERE (t.id, t_old.id) IN ((1,2), (2,1));
以下的
UPDATE
是有效的,尽管预计它不应该生效。约束被定义为INITIALLY IMMEDIATE
,而我没有使用SET CONSTRAINTS
。我是否遗漏了什么或者这是一个(相当无害的)bug?
2)修改数据的CTE
因此,修改数据的CTE也可以工作。尽管它会在使用
NOT DEFERRED
的主键时失败:WITH x AS (UPDATE t SET id = 1 WHERE id = 2)
UPDATE t SET id = 2 WHERE id = 1;
我引用CTE手册中的内容:
WITH语句中的子语句是同时与主查询并发执行的。因此,在WITH语句中使用数据修改语句时,指定更新实际发生的顺序是不可预测的。所有语句都使用相同的快照(参见第13章),因此它们不能“看到”目标表上其他语句对其产生的影响。
3)在一个事务中进行多个UPDATE语句
没有SET CONSTRAINTS,这将导致唯一性冲突-正如所预期的那样。
BEGIN;
-- SET CONSTRAINTS t_pkey DEFERRED;
UPDATE t SET id = 2 WHERE txt = 'one';
UPDATE t SET id = 1 WHERE txt = 'two';
COMMIT;