Oracle Apex second Trigger on table throwing mutating error - oracle

I have table p_it_people with structure as below and trigger created on it.
CREATE TABLE "P_IT_PEOPLE"
( "PERSON_ID" NUMBER NOT NULL ENABLE,
"PERSON_NAME" VARCHAR2(255) NOT NULL ENABLE,
"PERSON_EMAIL" VARCHAR2(255) NOT NULL ENABLE,
"PERSON_ROLE" VARCHAR2(30) NOT NULL ENABLE,
"USERNAME" VARCHAR2(255) NOT NULL ENABLE,
"ASSIGNED_DEPT" NUMBER,
"CREATED_ON" DATE NOT NULL ENABLE,
"CREATED_BY" VARCHAR2(255) NOT NULL ENABLE,
"MODIFIED_ON" DATE,
"MODIFIED_BY" VARCHAR2(255),
"PERSON_PASSWORD" VARCHAR2(100),
"APPROVER" VARCHAR2(50),
CONSTRAINT "P_IT_PEOPLE_PK" PRIMARY KEY ("PERSON_ID")
USING INDEX ENABLE,
CONSTRAINT "P_IT_PEOPLE_NAME_UK" UNIQUE ("PERSON_NAME")
USING INDEX ENABLE,
CONSTRAINT "P_IT_PEOPLE_USERNAME_UK" UNIQUE ("USERNAME")
Existing trigger on the table:
CREATE OR REPLACE EDITIONABLE TRIGGER "P_IT_PEOPLE_BIU"
before insert or update on p_it_people
for each row
begin
if inserting then
if :NEW.PERSON_ID is null then
:NEW.PERSON_ID := it_api.gen_pk;
end if;
:NEW.CREATED_ON := sysdate;
:NEW.CREATED_BY := nvl(v('APP_USER'),USER);
end if;
if updating then
:NEW.MODIFIED_ON := sysdate;
:NEW.MODIFIED_BY := nvl(v('APP_USER'),USER);
end if;
end;
Apart from this i want to create another trigger which would send email whenever new entry is made .
I deployed this trigger:
CREATE OR REPLACE EDITIONABLE TRIGGER "P_IT_ISSUES_AIU_NEW_PASSWORD"
AFTER
insert on P_IT_PEOPLE
for each row
DECLARE
v_person_id number;
v_username varchar2(50);
v_Email varchar2(255);
Begin
select person_id,username,person_email into v_person_id,v_username,v_email from p_it_people where person_id=v_person_id;
APEX_MAIL.SEND(
p_to => v_email,
p_from => v_email,
p_body => 'Your account has been created ' ||chr(10)||
' Username'|| v_username||chr(10)||
' Password'||v_username ,
p_subj => 'New User');
end;
Now when i try inserting row, it is throwing error-p_it_people is mutating. How can i counter this?

You are selecting from the same table as the row-level trigger is firing on - exactly what causes "table is mutating". But in this case you don't even need to. Just use the :NEW pseudo-record like this:
CREATE OR REPLACE EDITIONABLE TRIGGER "P_IT_ISSUES_AIU_NEW_PASSWORD"
AFTER
insert on P_IT_PEOPLE
for each row
Begin
APEX_MAIL.SEND(
p_to => :NEW.person_email,
p_from => :NEW.person_email ,
p_body => 'Your account has been created ' ||chr(10)||
' Username'|| :NEW.username||chr(10)||
' Password'||:NEW.username ,
p_subj => 'New User');
end;

Related

automatic partition naming for range partitioning

I have a table like this
CREATE TABLE data_audit(
id_col NUMBER(*,0) NOT NULL ENABLE,
col_2 VARCHAR2(10) NOT NULL ENABLE,
col_3 NUMBER(*,0) NOT NULL ENABLE,
col_4 VARCHAR2(10) NOT NULL ENABLE,
col_5 VARCHAR2(10) NOT NULL ENABLE,
created_at TIMESTAMP (3) DEFAULT current_timestamp,
CONSTRAINT DATA_AUDIT_PK PRIMARY KEY (col_2,col_3,col_4)
USING INDEX ENABLE
)
PARTITION BY RANGE(created_at)
(
PARTITION p2022_jan
VALUES LESS THAN (TO_DATE('01-jan-2022')),
PARTITION p2022_feb
VALUES LESS THAN (TO_DATE('01-feb-2022')),
PARTITION p2022_mar
VALUES LESS THAN (TO_DATE('01-mar-2022'))
)
Here - in above example - i need to explicitly mention the name in DDL
I want to create new partition automatically for every month data
How can i achieve it naming it automatically - i am ok with any random name of partition
I am using oracle - Oracle Database 19c Enterprise Edition Release 19.0.0.0
Instead of a RANGE partition I would suggest an INTERVAL partition:
CREATE TABLE DATA_AUDIT (
id_col NUMBER(*,0) NOT NULL ENABLE,
col_2 VARCHAR2(10) NOT NULL ENABLE,
col_3 NUMBER(*,0) NOT NULL ENABLE,
col_4 VARCHAR2(10) NOT NULL ENABLE,
col_5 VARCHAR2(10) NOT NULL ENABLE,
CREATED_AT TIMESTAMP (3) default current_timestamp ,
CONSTRAINT DATA_AUDIT_PK PRIMARY KEY (col_2,col_3,col_4) USING INDEX ENABLE
)
partition by range (CREATED_AT) INTERVAL (INTERVAL '1' MONTH)
(PARTITION p2021_dec VALUES LESS THAN (TIMESTAMP '2022-01-01 00:00:00'));
Then Oracle will create new partition automatically every months.
For renaming you can runs this procedure by daily scheduler job as proposed by Barbaros Özhan.
PROCEDURE RenamePartitions IS
ts TIMESTAMP;
newName VARCHAR2(30);
CURSOR TabPartitions IS
SELECT TABLE_NAME, PARTITION_NAME, HIGH_VALUE
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = 'DATA_AUDIT'
ORDER BY 1,2;
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET DDL_LOCK_TIMEOUT = 180';
FOR aPart IN TabPartitions LOOP
EXECUTE IMMEDIATE 'BEGIN :ret := '||aPart.HIGH_VALUE||'; END;' USING OUT ts;
ts := ADD_MONTHS(ts, -1);
newName := 'p'||TO_CHAR(ts,'yyyy_mon', 'NLS_DATE_LANGUAGE = american');
IF aPart.PARTITION_NAME <> newName THEN
EXECUTE IMMEDIATE 'ALTER TABLE '||aPart.TABLE_NAME||' RENAME PARTITION '||aPart.PARTITION_NAME||' TO '||newName;
END IF;
END LOOP;
END RenamePartitions;
Or see a more generic one: Partition table rename automatically in ORACLE
Assume that the table only has the first partition(p2022_jan) and you'll add new partitions to the table every month, then firstly create a stored procedure such as
CREATE OR REPLACE PROCEDURE Pr_Add_Part_to_Data_Audit is
v_ddl VARCHAR2(32767);
v_date DATE := TO_DATE(TO_CHAR(sysdate,'yyyy-mm-')||'01','yyyy-mm-dd');
BEGIN
v_ddl :='ALTER TABLE data_audit ADD PARTITION p'||TO_CHAR(v_date,'yyyy')||'_'||TO_CHAR(v_date,'mon')||' VALUES LESS THAN ('''||v_date||''')';
EXECUTE IMMEDIATE v_ddl;
END;
/
then, call that from a scheduler at the beginning of the upcoming months such as
DECLARE
v_job_name VARCHAR2(32) := 'jb_add_part_data';
BEGIN
DBMS_SCHEDULER.CREATE_JOB(job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'Pr_Add_Part_to_Data_Audit',
start_date => TO_DATE('01-02-2021 01:00:10',
'DD-MM-YYYY HH24:MI:SS'),
repeat_interval => 'FREQ=MONTHLY; BYHOUR=1;',
auto_drop => false,
comments => 'Adds a new partition every month');
DBMS_SCHEDULER.ENABLE(v_job_name);
END;
/
Here the answergiven by Wernfried Domscheit - is correct
thank you for your Answer - it showed the way of controlling partition name - in my case i didn't need to care about partition name - i just needed to make sure - new partition is created with new name - so i used first half of your comment -
to verify it - i used it with DAY - partitioning
CREATE TABLE DATA_AUDIT (
id_col NUMBER(*,0) NOT NULL ENABLE,
col_2 VARCHAR2(10) NOT NULL ENABLE,
col_3 NUMBER(*,0) NOT NULL ENABLE,
col_4 VARCHAR2(10) NOT NULL ENABLE,
col_5 VARCHAR2(10) NOT NULL ENABLE,
CREATED_AT TIMESTAMP (3) default current_timestamp ,
CONSTRAINT DATA_AUDIT_PK PRIMARY KEY (col_2,col_3,col_4) USING INDEX ENABLE
)
partition by range (CREATED_AT) INTERVAL (INTERVAL '1' DAY)
(PARTITION p2021_dec VALUES LESS THAN (TIMESTAMP '2022-01-01 00:00:00'));
and then it created partitions like
partition name - table name
P2021_DEC - DATA_PURGE_AUDIT
SYS_P8592 - DATA_PURGE_AUDIT

Need to accept comma separated inputs from the stored procedure and have to process as I have explained in the below body but getting compilation err

CREATE TABLE STAGING
(
E_ID NUMBER(10),
E_NAME VARCHAR2(30),
E_LOC VARCHAR2(30),
VALIDATION_STATUS varchar2(30),
validation_msg varchar2(30),
req_id number(10)
);
INSERT INTO staging VALUES(1, 'A', 'AA', NULL, NULL, 1);
INSERT INTO staging VALUES(2, 'B', 'BB', NULL, NULL, 1);
INSERT INTO staging VALUES(3, 'C', 'CC', NULL, NULL, 1);
INSERT INTO staging VALUES(NULL, 'D', 'DD', NULL, NULL, 2);
INSERT INTO staging VALUES(NULL, 'E', 'EE', NULL, NULL, 2);
INSERT INTO staging VALUES(NULL, 'F', 'GG', NULL, NULL, 2);
CREATE TABLE tab_ref
(
ref_id number(10),
ref_name varchar2(30)
);
INSERT INTO tab_ref VALUES(1, 'aa');
INSERT INTO tab_ref VALUES(2, 'bb');
INSERT INTO tab_ref VALUES(3, 'cc');
INSERT INTO tab_ref VALUES(4, 'dd');
CREATE TABLE tab_ref_2
(
ref_id number(10),
ref_name varchar2(30)
);
INSERT INTO tab_ref_2 VALUES(1, 'ee');
INSERT INTO tab_ref_2 VALUES(2, 'ff');
INSERT INTO tab_ref_2 VALUES(3, 'gg');
INSERT INTO tab_ref_2 VALUES(4, 'hh');
CREATE TABLE SUMMARY_TAB
(
TOT_RECORDS NUMBER(10,0),
SUCCESS_RECORDS NUMBER(10,0),
FAILED_RECORDS NUMBER(10,0),
process_status varchar2(30)
);
CREATE TABLE TARGET_TAB
(
E_ID NUMBER(10,0),
E_NAME VARCHAR2(30),
E_LOC VARCHAR2(30)
);
Stored procedure:
create or replace procedure sp_stage_target(iv_req_id IN sys.OdciNumberList,ov_err_msg OUT varchar2) is
lv_succ_rec number(30);
lv_fail_rec number(30);
lv_count_ref number(10);
lv_count_ref2 number(10);
lv_threshold_cnt number(10);
lv_RejectedCount number(10);
lv_status varchar2(30);
begin
lv_succ_rec := 0;
lv_fail_rec := 0;
lv_threshold_cnt := 5;
/*First checking whether data is present in reference table or not.
If data is not present then process should stop*/
select count(1) into lv_count_ref from tab_ref;
select count(1) into lv_count_ref2 from tab_ref_2;
if lv_count_ref = 0 then
ov_err_msg := 'Records are not present in the reference table !!Cannot proceed';
elsif lv_count_ref2 = 0 then
ov_err_msg := 'Records are not present in the reference table !!Cannot proceed';
else
dbms_output.put_line('Data are present into reference tables');
merge into staging d
using (
select 'Fail' as validation_status, t.column_value as req_id
from table(iv_req_id) t
) s
on (d.req_id = s.req_id)
when matched then
update set
d.validation_status = s.validation_status
, d.validation_msg = case
when e_id is null then 'Id is not present'
else 'Id is longer than expected'
end
where e_id is null OR LENGTH(e_id) > 4;
lv_RejectedCount := SQL%ROWCOUNT;
end if;
--If rejected count is less than lv_threshold_cnt i.e 5
--then success records will go in target_tab and failed records will go in reject_tab
if lv_RejectedCount <= lv_threshold_cnt then
lv_status := 'Success';
dbms_output.put_line('Success');
merge into target_tab t
using (
select e_id, e_name, e_loc
from staging
where validation_status is null and req_id in (select column_value from table(iv_req_id))
) s
on (t.e_id = s.e_id)
when matched then
update set
t.e_name = s.e_name,
t.e_loc = s.e_loc
when not matched then
insert (t.e_id,t.e_name,t.e_loc)
values (s.e_id,s.e_name,s.e_loc);
lv_succ_rec := SQL%ROWCOUNT;
end if;
insert into reject_tab
select e_id, e_name, e_loc, validation_status,validation_msg
from staging
where validation_status = 'Fail' and req_id in (select column_value from table(iv_req_id));
lv_fail_rec := SQL%ROWCOUNT;
--In Summary table keeping track of all the records i.e success record, failed records
dbms_output.put_line('Inserting into Summary table');
insert into summary_tab(tot_records, success_records, failed_records, process_status)
values (lv_succ_rec + lv_fail_rec, lv_succ_rec, lv_fail_rec, lv_status);
ov_err_msg := 'Procedure completed succesfully';
end;
Calling Procedure:
set serveroutput on;
declare
err_msg;
begin
sp_main_target(sys.OdciNumberList(1,2),err_msg);
dbms_output.put_line(err_msg);
end;
Getting compilation error and also I am not not how to process for individually for each request_id and process so have highlighted the requirement in comment block.
Error :
I wanted to create a stored procedure that will handle all the below points and I have tried but not been able to get the results.
The stored procedure should accept multiple input parameters while calling a procedure and should process for every request-id given in the parameter with comma-separated.
Then stored procedure will check whether data is present or not in the ref table (tab_ref & tab_ref_2). If data is present then only the process should start otherwise it will not proceed further.
Then it will check the data in the staging table and will do validation for e_id is null or not or its length should not exceed the given limit. For every failed validation it will update the validation status and validation msg column and have to keep count of rejected columns.
After validation, if the threshold count is less then the lv_threshold_count then insertion will happen in both the tables with status as 'Success 'i.e target table and rejected table with validation_status as null and Fail respectively.
If threshold count is more than the lv_threshold_count then it will insert into the rejected table with status as 'Fail'.
Then at last it will show all the records count into the summary table.
You start an IF on line 20 of your procedure, but you don't have a corresponding END IF.
if lv_count_ref = 0 then

PLS-00049: bad bind variable 'NEW.NEW_SKILL_DESC'

When I run the trigger the PLS-00049: bad bind variable 'NEW.NEW_SKILL_DESC' problems occur. The problem occurs in the: New section. This is the first time I am auditing a database query.
CREATE OR REPLACE TRIGGER lds_skill_trig
BEFORE INSERT OR DELETE OR UPDATE ON LDS_SKILL
FOR EACH ROW
ENABLE
DECLARE
v_user VARCHAR2(30);
v_date VARCHAR2(30);
BEGIN
SELECT user, TO_CHAR(sysdate, 'DD/M0N/YYYY HH24:MI:SS')
INTO v_user, v_date FROM dual;
IF INSERTING THEN
INSERT INTO db_lds_skill(new_skill_desc, old_skill_desc,user_name,
entry_date, operation)
VALUES(:NEW.new_skill_desc, NULL, v_user, v_date, 'Insert');
ELSIF DELETING THEN
INSERT INTO db_lds_skill(new_skill_desc, old_skill_desc, user_name,
entry_date, operation)
VALUES(NULL, :OLD.new_skill_desc, v_user, v_date, 'Delete');
ELSIF UPDATING THEN
INSERT INTO db_lds_skill(new_skill_desc, old_skill_desc, user_name,
entry_date, operation)
VALUES(:NEW.new_skill_desc, :OLD.new_skill_desc, v_user, v_date,'update');
END IF;
END;
This is the table for db_lds_skill where the audit record i want to save.
CREATE TABLE DB_LDS_SKILL
(NEW_SKILL_DESC VARCHAR2(30),
OLD_SKILL_DESC VARCHAR2(30),
USER_NAME VARCHAR2(30),
ENTRY_DATE VARCHAR2(30),
OPERATION VARCHAR2(30)
);
It seems you are adding wrong column name in the :NEW.new_skill_desc, in The :new. you have to specific the column for the table LDS_SKILL table, not db_lds_skill
The below I created locally and it was working fine, Note that I replaced to_date with to_char and replaced M0N with MON
drop table db_lds_skill
/
create table db_lds_skill
(new_skill_desc varchar2(100) null,
old_skill_desc varchar2(100) null,
user_name varchar2(100) null,
entry_date varchar2(100),
operation varchar2(100) null
)
/
drop table LDS_SKILL
/
create table LDS_SKILL
(new_skill_desc varchar2(100) null,
old_skill_desc varchar2(100) null,
user_name varchar2(100) null,
entry_date varchar2(100) nulll,
operation varchar2(100) null
)
/
CREATE OR REPLACE TRIGGER lds_skill_trig
BEFORE INSERT OR DELETE OR UPDATE ON LDS_SKILL
FOR EACH ROW
ENABLE
DECLARE
v_user VARCHAR2(30);
v_date VARCHAR2(30);
BEGIN
SELECT user, TO_CHAR(sysdate, 'DD/MON/YYYY HH24:MI:SS')
INTO v_user, v_date FROM dual;
IF INSERTING THEN
INSERT INTO db_lds_skill(new_skill_desc, old_skill_desc,user_name,
entry_date, operation)
VALUES(:NEW.new_skill_desc, NULL, v_user, v_date, 'Insert');
ELSIF DELETING THEN
INSERT INTO db_lds_skill(new_skill_desc, old_skill_desc, user_name,
entry_date, operation)
VALUES(NULL, :OLD.new_skill_desc, v_user, v_date, 'Delete');
ELSIF UPDATING THEN
INSERT INTO db_lds_skill(new_skill_desc, old_skill_desc, user_name,
entry_date, operation)
VALUES(:NEW.new_skill_desc, :OLD.new_skill_desc, v_user, v_date,'update');
END IF;
END;
/
insert into LDS_SKILL (new_skill_desc) values('pp')
/
commit
/

IF-ELSE statement inside trigger in oracle

Here are the columns in my table, TB_KELUHAN
"IDKELUHAN" NUMBER(20,0) NOT NULL ENABLE,
"NAMA" VARCHAR2(10 BYTE),
"IDUNIT" NUMBER(10,0),
"TGL_KELUHAN" DATE DEFAULT sysdate,
"KELUHAN" VARCHAR2(200 BYTE),
"STATUS" VARCHAR2(10 BYTE),
"IDPEGAWAI" NUMBER(10,0),
"TGL_SELESAI" DATE DEFAULT sysdate,
"ID_JENISKELUHAN" NUMBER(5,0),
CONSTRAINT "TB_KELUHAN_PK" PRIMARY KEY ("IDKELUHAN")
I want a trigger that will update a row's TGL_SELESAI column to SYSDATE, when a row's STATUS becomes 'SELESAI'. Here is the text of the trigger I've tried:
TRIGGER SELESAI
AFTER UPDATE OF STATUS ON TB_KELUHAN
FOR EACH ROW
DECLARE
TGL_SELESAI DATE;
BEGIN
IF :new.STATUS = 'SELESAI'
THEN
TGL_SELESAI:=SYSDATE;
END IF;
END;
When I change the value of STATUS to "SELESAI", the corresponding TGL_SELESAI did not change. Why?
Your original code was setting a local PL/SQL variable, not the row's column and you were creating an AFTER UPDATE trigger, not a BEFORE UPDATE trigger. Try this:
CREATE OR REPLACE TRIGGER SELESAI
BEFORE UPDATE OF STATUS ON TB_KELUHAN
FOR EACH ROW
BEGIN
IF :new.STATUS = 'SELESAI'
THEN
:new.TGL_SELESAI := SYSDATE;
END IF;
END;

Error at line 14: PL/SQL: SQL Statement ignored

I keep getting the error below and I can't figure out why. I've included the tables in the code and then also the code portion that is presenting the error.
Tables in the code:
CREATE TABLE Employee (
emp_id number(8) primary key,
f_name VarChar2(20),
l_name VarChar2(20),
address VarChar2(40),
city VarChar2(20),
state Char(2),
zip Number(5),
phone_Number Number(10),
email_address VarChar2(30),
dept_id number(8) references department(Dept_ID),
office_location VarChar2(30)
);
CREATE TABLE audit_detail (
audit_detail_id number(8) primary key,
field varchar2(30),
old_value varchar2(30),
new_value varchar2(30)
);
CREATE TABLE audit_trail (
audit_trail_id number(8) primary key,
user_id number(8)references user_id_table(user_id),
table_name VarChar2(25),
process VarChar2(25),
emp_id number(8)references employee(emp_id),
timestamp Date
);
Create table Department (
dept_id number(8) primary key,
dept_name VarChar2(20) not null,
dept_start_date date
);
create table user_id_table(
user_id number(8) primary key,
emp_id number(8) references Employee(emp_id)
);
CREATE SEQUENCE audit_seq;
This is the portion that is presenting the error, Specifically the elsif Deleting portion
CREATE OR REPLACE TRIGGER audit_employee
AFTER INSERT OR UPDATE OR DELETE ON Employee
FOR EACH ROW
DECLARE
timestamp DATE;
session_user number(8);
BEGIN
timestamp := SYSDATE;
session_user := USERENV('SESSION_USER');
IF INSERTING THEN
INSERT INTO audit_trail VALUES
(Audit_seq.NEXTVAL, session_user, 'Employee', 'INSERT', :new.emp_id, timestamp);
ElSIF DELETING THEN
INSERT INTO audit_trail Values
(Audit_seq.NEXTVAL, session_user, 'Employee', 'DELETE', :old.emp_id, timestamp);
Else
INSERT INTO audit_trail
Values(Audit_seq.NEXTVAL, session_user, 'Employee', 'UPDATE', :old.emp_id);
IF UPDATING ('f_name') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'f_name', :old.f_name, :new.f_name);
ELSIF UPDATING('l_name') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'l_name', :old.l_name, :new.l_name);
ELSIF UPDATING('address') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'address', :old.address, :new.address);
ELSIF UPDATING('city') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'city', :old.city, :new.city);
ELSIF UPDATING('state') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'state', :old.state, :new.state);
ELSIF UPDATING('zip') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'zip', :old.zip, :new.zip);
ELSIF UPDATING('phone_Number') THEN
INSERT INTO Audit_detail VALUES
(Audit_seq.CURRVAL, 'phone_Number', :old.phone_number, :new.phone_number);
ELSIF UPDATING('email_address') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'email_address', :old.email_address, :new.email_address);
ELSIF UPDATING('dept_id') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'dept_id', :old.dept_id, :new.dept_id);
ELSIF UPDATING('office_location') THEN
INSERT INTO audit_detail VALUES
(Audit_seq.CURRVAL, 'office_location', :old.office_location, :new.office_location);
End IF;
End IF;
End;
/
Your else statement after the deleting has 5 columns whereas audit_trail has 6.
ElSIF DELETING THEN
INSERT INTO audit_trail
Values ( Audit_seq.NEXTVAL, session_user, 'Employee'
, 'DELETE', :old.emp_id, timestamp);
Else
INSERT INTO audit_trail
Values (Audit_seq.NEXTVAL, session_user, 'Employee'
, 'UPDATE', :old.emp_id );
You're also referencing columns in lower case not upper, UPDATING ('L_NAME'). I'm not sure whether that would cause a problem.
You're doing a lot of implicit number to character conversion which will eventually catch you out and table_name in audit_trail should by 30 characters not 25. Why risk it?

Resources