我应该修复数据库层中的问题,而不是代码中的问题,但它有点复杂。我用谷歌搜索,但找不到解决方案:(
数据库版本: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,
);
为简单起见,我们先调用第一个“ID”,第二个可以保持OP_DAYS,“Range”可以保持最后一个。
我必须确保没有插入重叠记录。这意味着ID和OP_DAYS和范围不匹配。
必须满足以上条件才能让DB拒绝行的插入。所以必须有一个ID匹配,一个OP_DAYS垫和一个Range匹配,在这种情况下,数据应该被拒绝。
还有一件事:如果它更容易,我可以制作OP_DAYS 7列,所以每天都会有它的单独列。只有在没有这种改变的情况下才能使这种约束变得非常困难或不可能。
答案 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)
不要使用触发器来强制实施数据一致性。编写一个执行数据库端验证的模块。