Note that there are some explanatory texts on larger screens.

plurals
  1. POOracle 10g and data validation in a trigger before row update
    primarykey
    data
    text
    <p>I am using Oracle 10g and I have the following table:</p> <pre><code>create table DE_TRANSFORM_MAP ( DE_TRANSFORM_MAP_ID NUMBER(10) not null, CLIENT NUMBER(5) not null, USE_CASE NUMBER(38) not null, DE_TRANSFORM_NAME VARCHAR2(100) not null, IS_ACTIVE NUMBER(1) not null ) </code></pre> <p>That maps to an entry in the following table:</p> <pre><code>create table DE_TRANSFORM ( DE_TRANSFORM_ID NUMBER(10) not null, NAME VARCHAR2(100) not null, IS_ACTIVE NUMBER(1) not null ) </code></pre> <p>I would like to enforce the following rules:</p> <ul> <li>Only one row in DE_TRANSFORM_MAP with the same CLIENT and USE_CASE can have IS_ACTIVE set to 1 at any time</li> <li>Only one row in DE_TRANSFORM with the same NAME and IS_ACTIVE set to 1 at any time</li> <li>A row in DE_TRANSFORM cannot have IS_ACTIVE changed from 1 to 0 if any rows in DE_TRANSFORM_MAP have DE_TRANSFORM_NAME equal to NAME and IS_ACTIVE set to 1</li> </ul> <p>Does this make sense?</p> <p>I have tried to write a stored proc that handles this:</p> <pre><code>create or replace trigger DETRANSFORMMAP_VALID_TRIG after insert or update on SERAPH.DE_TRANSFORM_MAP for each row declare active_rows_count NUMBER; begin select count(*) into active_rows_count from de_transform_map where client = :new.client and use_case = :new.use_case and is_active = 1; if :new.is_active = 1 and active_rows_count &gt; 0 then RAISE_APPLICATION_ERROR(-20000, 'Only one row with the specified client, use_case, policy_id and policy_level may be active'); end if; end; </code></pre> <p>When I do the following it works as expected, I get an error:</p> <pre><code>insert into de_transform_map (de_transform_map_id, client, use_case, de_transform_name, is_active) values (detransformmap_id_seq.nextval, 6, 0, 'TEST', 1); insert into de_transform_map (de_transform_map_id, client, use_case, de_transform_name, is_active) values (detransformmap_id_seq.nextval, 6, 1, 'TEST', 1); </code></pre> <p>But if I then do this:</p> <pre><code>update de_transform_map set use_case = 0 where use_case = 1 </code></pre> <p>I get the following:</p> <pre><code>ORA-04091: table DE_TRANSFORM_MAP is mutating, trigger/function may not see it </code></pre> <p>How can I accomplish my validation?</p> <p>EDIT: I marked Rene's answer as correct because I think the most correct and elegant way to do this is with a compound trigger but our production DB is still just 10g, we are updating to 11g early next year and I will rewrite the trigger then. Until then, I have a blanket trigger that will assert that no rows are duplicated, here it is:</p> <pre><code>create or replace trigger DETRANSFORMMAP_VALID_TRIG after insert or update on DE_TRANSFORM_MAP declare duplicate_rows_exist NUMBER; begin select 1 into duplicate_rows_exist from dual where exists ( select client, use_case, count(*) from de_transform_map where is_active = 1 group by client, use_case having count(*) &gt; 1 ); if duplicate_rows_exist = 1 then RAISE_APPLICATION_ERROR(-20000, 'Only one row with the specified client, use_case may be active'); end if; end; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload