使用临时键重叠更新多个记录

时间:2013-02-26 12:12:06

标签: sql-server-2008 postgresql oracle10g sql-update unique-constraint

我在DB上有一个表格,其中包含以下字段:PK DOC_IDSECTION_IDSET_IDCELL_ID。您可以推断,这是指一组Excel电子表格。

除了这些字段外,我还有一个CELL_ROW字段和CELL_COL字段。 使用SET_ID唯一),它们会形成替代密钥。

所以,至少在理论上,如果我想交换两个单元格的坐标,我需要释放该约束,或者使用第三个临时自由位置(例如 A100000 )。 / p>

假设我有以下单元格:

 DOC_ID | SECTION_ID | SET_ID | CELL_ID | CELL_ROW | CELL_COL
--------|------------|--------|---------|----------|----------
   5    |     456    |  8778  |  15045  |    5     |    4
   5    |     456    |  8778  |  15048  |    5     |    5 

假设我有以下临时表,我在其中对主表执行UPDATE

 DOC_ID | SECTION_ID | SET_ID | CELL_ID | CELL_ROW | CELL_COL
--------|------------|--------|---------|----------|----------
   5    |     456    |  8778  |  15045  |    5     |    5
   5    |     456    |  8778  |  15048  |    5     |    4

理论上,UPDATE应该引发例外......

但只是尝试过,它有效!

你能解释一下为什么吗? Oracle是否将其作为原子操作执行,因此仅在整个操作之后检查约束(而不是每条记录的记录)?

MS SQL Server 2008 r2和Postgres在这种情况下的表现如何?

2 个答案:

答案 0 :(得分:1)

我在Postgresql中尝试了它并且正如预期的那样引发了重复键错误:

create table t (
    doc_id integer,
    section_id integer,
    set_id integer,
    cell_id integer,
    cell_row integer,
    cell_col integer,
    primary key (doc_id, section_id, set_id, cell_id),
    unique (set_id, cell_row, cell_col)
);

insert into t (doc_id, section_id, set_id, cell_id, cell_row, cell_col)
values
(5, 456, 8778, 15045, 5, 4),
(5, 456, 8778, 15048, 5, 5);

create temporary table t_temp (
    doc_id integer,
    section_id integer,
    set_id integer,
    cell_id integer,
    cell_row integer,
    cell_col integer
);

insert into t_temp (doc_id, section_id, set_id, cell_id, cell_row, cell_col)
values
(5, 456, 8778, 15045, 5, 5),
(5, 456, 8778, 15048, 5, 4);

update t
set
    cell_col = t_temp.cell_col
from t_temp
where
    t.doc_id = t_temp.doc_id
    and t.section_id = t_temp.section_id
    and t.set_id = t_temp.set_id
    and t.cell_id = t_temp.cell_id
;
ERROR:  duplicate key value violates unique constraint "t_set_id_cell_row_cell_col_key"
DETAIL:  Key (set_id, cell_row, cell_col)=(8778, 5, 5) already exists.

如果约束设置为deferrable,我可以这样做。检查该关键字的create table语句。

答案 1 :(得分:1)

PostgreSQL将抛出错误,除非您推迟唯一约束(然后您不能将其用作外键)。我不确定SQL Server。

简而言之,你可能想把它称为Postgres或PostgreSQL。将其称为Postgre表明您与社区的联系太少而无法纠正。

有关PostgreSQL的更多信息

PostgreSQL在元组更新时检查元组约束。这意味着即使在以不违反唯一约束的原子方式更新集合的情况下,也会违反唯一约束。这导致了一些有趣的解决方法,例如将一个整数键乘以该集合的-1,然后在下一次更新中再次乘以-1并添加一个。