【问题标题】:SQL Oracle constraint value unique among multiple columnsSQL Oracle 约束值在多列之间唯一
【发布时间】:2013-11-02 17:07:17
【问题描述】:

假设我在一个表中有 3 列 - A、B 和 C。我想确保如果我在 A 列中插入一些值(比如 x),我不能插入一个包含 B 或 C 的元组等于 x,即对于所有元组,值 x 对于列 A 应保持唯一。

请注意,对于其他一些元组,x 可以在 A 中重复。

我知道 SQL 中的 UNIQUE 子句,但这只是为了确保某个值在特定列中只出现一次。由于 Oracle 中的 CHECK 语句不允许子查询,我不知道如何实现它。

编辑(添加更多信息)

主键是 Employee_Number,而有问题的 3 列是 LandlineNo、MobileNo 和 VOIP。因此假设这是一个条目:

Employee_Number = 1, LandlineNo = x, MobileNo = y, VOIP = z

那么另一个元组的这个条目将不被允许 -

Employee_Number = 2, LandlineNo = a, MobileNo = x, VOIP = c

另一方面,这个就可以了(是的,2名员工可以拥有相同数量的相同类型)

Employee_Number = 2, LandlineNo = x, MobileNo = b, VOIP = c

【问题讨论】:

  • 你能用好行和坏行的例子来扩展你的问题吗?表的结构和主键是什么?
  • 你还在为这个桌子设计而苦恼吗?您要求 ist 保证每个数字都属于某种类型。那么为什么没有一个“数字”表,主键是数字(或者一个 id 加上对数字的唯一约束,如果你愿意的话),然后你就有一个列类型。因此,每个数字都是唯一的并且具有一种类型。然后在您的员工表中,您只有该数字表的三个外键(即三个数字或三个 ID)。
  • 您使用的是哪个版本的 Oracle?
  • 同意@ThorstenKettner——这绝对是一个有问题的数据模型。
  • 这是失败的数据模型。依赖于普通数据库约束的简单、更好的建模将产生简单、更好的结果。听@ThorstenKettner 。

标签: sql oracle tuples multiple-columns unique-constraint


【解决方案1】:
CREATE MATERIALIZED VIEW mv_my
BUILD IMMEDIATE
REFRESH FAST ON COMMIT AS
SELECT DISTINCT
    CASE 
        WHEN t2.Employee_Number IS NOT NULL THEN 1
        WHEN t3.Employee_Number IS NOT NULL THEN 1
        WHEN t4.Employee_Number IS NOT NULL THEN 1
        ELSE 0
    END AS wrong
FROM table t1
    LEFT JOIN table t2 ON t2.MobileNo = t1.LandlineNo AND t2.Employee_Number != t1.Employee_Number
    LEFT JOIN table t3 ON t3.VOIP = t1.LandlineNo AND t3.Employee_Number != t1.Employee_Number
    LEFT JOIN table t4 ON t4.VOIP = t1.MobileNo AND t4.Employee_Number != t1.Employee_Number
/

ALTER TABLE mv_my ADD CHECK(wrong = 0)
/

取决于您的 oracle 版本 (doc),它可能有效,也可能无效

【讨论】:

    【解决方案2】:
    create table table1(
       a varchar2(20) not null,
       b varchar2(20) not null,
       c varchar2(20) not null
    )
    /
    create table ctrs (
       val varchar2(20) unique,
       ctr_a int,
       ctr_b int,
       ctr_c int,
       check(ctr_a*ctr_b+ctr_a*ctr_c+ctr_b*ctr_c=0)
    )
    /
    create trigger table1_trg 
    before insert or update or delete on table1
    for each row
    begin
       if deleting then 
          update ctrs set ctr_a = ctr_a - 1 where val = :old.a;
          update ctrs set ctr_b = ctr_b - 1 where val = :old.b;
          update ctrs set ctr_c = ctr_c - 1 where val = :old.c;
       elsif inserting then
          merge into ctrs using (
            select :new.a as x from dual union all
            select :new.b as x from dual union all
            select :new.c as x from dual
          )
          on (val = x)
          when not matched then 
             insert (val, ctr_a, ctr_b, ctr_c) values (x, 0, 0, 0);
          update ctrs set ctr_a = ctr_a + 1 where val = :new.a;
          update ctrs set ctr_b = ctr_b + 1 where val = :new.b;
          update ctrs set ctr_c = ctr_c + 1 where val = :new.c;
       else
          update ctrs set ctr_a = ctr_a - 1 where val = :old.a;
          update ctrs set ctr_b = ctr_b - 1 where val = :old.b;
          update ctrs set ctr_c = ctr_c - 1 where val = :old.c;
          merge into ctrs using (
            select :new.a as x from dual union all
            select :new.b as x from dual union all
            select :new.c as x from dual
          )
          on (val = x)
          when not matched then 
             insert (val, ctr_a, ctr_b, ctr_c) values (x, 0, 0, 0);
          update ctrs set ctr_a = ctr_a + 1 where val = :new.a;
          update ctrs set ctr_b = ctr_b + 1 where val = :new.b;
          update ctrs set ctr_c = ctr_c + 1 where val = :new.c;
       end if;
    end;
    /
    

    fiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多