sql - 如何在 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 不接受这种语法。
两种经典方法:
- 有两个独特的约束
CREATE UNIQUE INDEX uidxA ON test A
并且CREATE UNIQUE INDEX uidxB ON test B
不起作用,因为那时我可以将 2 和 4 添加到“A”列 - 具有两列的唯一约束,
CREATE UNIQUE INDEX uidxB ON test (A, B)
因为这仅检查现有对。
(奖励问题:应该允许同一行的“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
解决方案
@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 触发器。语法可能是错误的,但想法应该飞。
推荐阅读
- java - 每次实例化类时如何实例化单独的bean成员
- unit-testing - 如何对文档具有给定权限进行单元测试?
- c++ - “void *”类型的值不能分配给“double *”类型的实体
- laravel - 以雄辩的方式附加到数组的字段
- amazon-web-services - Terraform:将预先存在的 aws 策略附加到预先存在的 aws 角色
- python - 是否可以让 numpy 从不同调用的分布中生成相同的随机数?
- bitmap - 如何平滑宽阶梯位图?
- azure - 适用于 Linux 容器的 Azure Web 应用服务未从 docker-compose 文件中获取环境变量
- ruby-on-rails - 如何在 ActiveRecord 中处理 Rails N:M/HABTM 关系?
- spring-batch - Spring Batch 团队是否提供读取 Excel 文件的内置方式?