I should fix a problem in the DB tier, not in the code, but it's a bit complex. I googled, but couldn't find the solution :(
DB version: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod
Okay, let's say I have a table with multiple row, but only these are interesting to us right now.
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,
);
For simplicity, lets call the first one "ID", 2nd one can stay OP_DAYS and "Range" the last one.
I have to make sure that no overlapping record is inserted. That means That ID AND OP_DAYS AND Range doesn't match.
Above criteria has to be ALL met for the DB to reject the insert of the row. So there has to ba an ID match, an OP_DAYS mats and a Range match, and in this case, the data should be rejected.
One more thing: if it makes it easier I can make the OP_DAYS 7 columns, so every day would have it's separate column. This is only if it makes it really hard or impossible to make this constraint without this change.
You cannot enforce a rule like this with a constraint. It can be done using triggers, which will be complex to code due to having to avoid the "mutating table" issue while still ensuring transaction integrity (so not using an autonomous transaction!)
There is also a method using materialized views with constraints that I have written about here on my blog (see first example). However, this is quite experimental and may not be practical in a real database (eg may adversely affect performance).
The most common solution is to write PL/SQL package APIs to perform the logic and force applications to use the API rather than inserting/updating the table directly.
here is the AFTER INSERT OR UPDATE Trigger, which check for intersection and raise an exception if one is found.
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;
/
Don't use triggers to enforce data consistency. Write a module that perform database side validation.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.