首页 > 解决方案 > 如何在 SQL (Oracle) 中执行跨列唯一约束

问题描述

如何在具有两列的 Oracle-DB 中具有唯一约束,这样一列或另一列中不得出现重复。

假设这张表

|id | A | B |
|---|---|---|
| 1 | 1 | 2 |
| 2 | 3 | 4 |

我不允许新行在“A”列中具有与“A”或“B”列中的值重复的值。

在上面的示例中:我可以将 5 添加到“A”列,但不能添加 1、2、3 或 4。

我的想法是做类似的事情:

CREATE UNIQUE INDEX crossTest ON test (
    SELECT t.A AS x FROM test t
    UNION ALL
    SELECT t.B AS x FROM test t
    )

但它不起作用,因为 Oracle 不接受这种语法。

两种经典方法:

(奖励问题:应该允许同一行的“A”和“B”可以相等)


示例的 SQL 脚本

CREATE TABLE test (id NUMBER (10) NOT NULL, a VARCHAR2(12), b VARCHAR2(12));
INSERT INTO test (id,a,b) VALUES(1, '1', '2');
INSERT INTO test (id,a,b) VALUES(2, '3', '4');

INSERT INTO test (id,a,b) VALUES(3, '4', 'x'); -> should fail
INSERT INTO test (id,a,b) VALUES(3, '5', 'x'); -> should work

标签: sqloracleoracle11gunique

解决方案


@Tejash 的回答给了我一个避免锁定或序列化的想法。您可以创建一个辅助表duet_index来生成包含所有行的扩展数据集。然后一个简单的触发器就可以解决问题,包括你的奖金问题。

例如:

create table duet_index (
  n number,
  constraint unique uq1 (n)
);

然后是触发器:

create or replace trigger test_trg
before insert on test
for each row
begin
  insert into duet_index (n) values (:new.a);
  if (:new.a <> :new.b) then
    insert into duet_index (n) values (:new.b);
  end if;
end;

请考虑我不擅长编写 Oracle 触发器。语法可能是错误的,但想法应该飞


推荐阅读