Oracle 10g - >创建复杂约束

时间:2013-09-27 13:37:04

标签: sql oracle constraints

我应该修复数据库层中的问题,而不是代码中的问题,但它有点复杂。我用谷歌搜索,但找不到解决方案:(

  

数据库版本:Oracle数据库10g企业版10.2.0.3.0版 - 产品

好吧,假设我有一个包含多行的表格,但现在只有这些对我们很有意思。

CREATE TABLE "TRANSPORT" 
(   "O_PREFIX" VARCHAR2(3 BYTE), 
    "O_NUMBER" NUMBER(4,0), 
    "O_SUFFIX" CHAR(1 BYTE), 
    "OP_DAYS" VARCHAR2(7 BYTE), 
    "VALID_FROM" DATE, 
    "VALID_TO" DATE, 
);
  • O_PREFIX + O_NUMBER + O_SUFFIX订单ID如下:AB2000S
  • OP_DAYS:标记运输发生的日期,即:1235 - >意思是第1天(星期一),第2天(星期二)等等...如果它每天发货,它看起来像:1234567,如果只在星期一发货:1
  • VALID_FROM + VALID_TO:为我们提供发货的范围。例如,如果VALID_FROM:01SEP13,VALID_TO:14OCT13和OP_DAYS为:15,则表示在9月1日至10月1日之间的每周一和周五发货。

为简单起见,我们先调用第一个“ID”,第二个可以保持OP_DAYS,“Range”可以保持最后一个。

我必须确保没有插入重叠记录。这意味着ID和OP_DAYS和范围不匹配。

  • ID匹配是直接的,它们是相同的String。
  • OP_DAYS匹配意味着有一个共同的号码,所以例如“1234”和“456”在我们的情况下匹配,但“123”和“456”不匹配。
  • 范围匹配表示日期重叠,例如“01SEP13-15SEP13”和“10SEP13-01OCT13”匹配,但“01SEP13-15SEP13”和“16SEP13-01OCT13”正常。

必须满足以上条件才能让DB拒绝行的插入。所以必须有一个ID匹配,一个OP_DAYS垫和一个Range匹配,在这种情况下,数据应该被拒绝。

还有一件事:如果它更容易,我可以制作OP_DAYS 7列,所以每天都会有它的单独列。只有在没有这种改变的情况下才能使这种约束变得非常困难或不可能。

3 个答案:

答案 0 :(得分:4)

您无法使用约束强制执行此类规则。它可以使用触发器完成,由于必须避免“变异表”问题,同时仍然确保事务完整性(因此使用自治事务!),因此代码很复杂。

还有一种使用具有约束的物化视图的方法,我已经写过here on my blog(参见第一个例子)。然而,这是非常实验性的,并且在真实数据库中可能不实用(例如可能对性能产生不利影响)。

最常见的解决方案是编写PL / SQL包API来执行逻辑并强制应用程序使用API​​,而不是直接插入/更新表。

答案 1 :(得分:2)

这里是AFTER INSERT OR UPDATE触发器,它检查交叉点并在发现异常时引发异常。

CREATE OR REPLACE TRIGGER transport_intersection_ck_trg
  AFTER INSERT OR UPDATE 
  ON transport
DECLARE
  cnt NUMBER;
BEGIN
  SELECT count(*) 
  INTO cnt
  FROM transport t1, transport t2
  WHERE t1.rowid != t2.rowid
  AND t1.PREFIX || t1."NUMBER" || t1.SUFFIX = t2.PREFIX || t2."NUMBER" || t2.SUFFIX
  AND 1 = CASE 
            WHEN INSTR(t1.op_days, 1) > 0 AND INSTR(t2.op_days, 1) > 0  THEN 1
            WHEN INSTR(t1.op_days, 2) > 0 AND INSTR(t2.op_days, 2) > 0  THEN 1
            WHEN INSTR(t1.op_days, 3) > 0 AND INSTR(t2.op_days, 3) > 0  THEN 1
            WHEN INSTR(t1.op_days, 4) > 0 AND INSTR(t2.op_days, 4) > 0  THEN 1
            WHEN INSTR(t1.op_days, 5) > 0 AND INSTR(t2.op_days, 5) > 0  THEN 1
            WHEN INSTR(t1.op_days, 6) > 0 AND INSTR(t2.op_days, 6) > 0  THEN 1
            WHEN INSTR(t1.op_days, 7) > 0 AND INSTR(t2.op_days, 7) > 0  THEN 1
            ELSE 0
          END
  AND  t1.valid_from >= t2.valid_to
  AND  t2.valid_from >= t1.valid_to
  ;        
  IF cnt > 0 THEN
    raise_application_error(-20000, 'intersection found');
  END IF;
END;
/

答案 2 :(得分:1)

不要使用触发器来强制实施数据一致性。编写一个执行数据库端验证的模块。

相关问题