Update trigger to add data from two different tables onto audit table - oracle

I've created a after update trigger and would like to add data from two different tables(GORADID and SPRIDEN) when the update fires. The both of the tables are connected by one column(PIDM), so therefore is it possible to also collect data from table 2 ? so far i been getting errors such as ORA: no bind variables..
I also tried doing a select statements. But also no luck. Any suggestions would help.
error: psl-00049: bad bind variable ':new.spriden_id'
error: psl-00049: bad bind variable ':new.spriden_first_name'
error: psl-00049: bad bind variable ':new.spriden_last_name'

Your trigger belongs to GORADID table and :new and :old represent this table
can you try change your trigger like this ?
CREATE OR REPLACE TRIGGER GORADID_UPDT_TRG1
AFTER UPDATE OF GORADID_ADDITIONAL_ID
ON GORADID
FOR EACH ROW
DECLARE
SZRGORA_AUDIT_USER_BANNER_ID VARCHAR2 (150 CHAR);
SZRGORA_AUDIT_STUDENT_BANNER VARCHAR2 (9 CHAR);
SZRGORA_AUDIT_USER_FIRST_NAME VARCHAR2 (150 CHAR);
SZRGORA_AUDIT_USER_LAST_NAME VARCHAR2 (150 CHAR);
SZRGORA_AUDIT_ADDITIONAL_ID VARCHAR2 (50 CHAR);
SPRIDEN_ID VARCHAR2 (9 CHAR);
BEGIN
SELECT USER INTO SZRGORA_AUDIT_USER_BANNER_ID FROM DUAL;
SELECT SPRIDEN_ID
INTO SZRGORA_AUDIT_STUDENT_BANNER
FROM SPRIDEN
WHERE SPRIDEN_PIDM =:old.GORADID_PIDM;
SELECT SPRIDEN_FIRST_NAME, SPRIDEN_LAST_NAME
INTO SZRGORA_AUDIT_USER_FIRST_NAME, SZRGORA_AUDIT_USER_LAST_NAME
FROM SATURN.SPRIDEN
WHERE SPRIDEN_PIDM = (SELECT PIDM
FROM SATURN.IDM_STAFF_AFF_ST
WHERE USERNAME = USER);
INSERT INTO SZRGORA_AUDIT
VALUES (SZRGORA_AUDIT_STUDENT_BANNER,
:new.GORADID_ADDITIONAL_ID,
:old.GORADID_ADDITIONAL_ID,
SZRGORA_AUDIT_USER_FIRST_NAME,
SZRGORA_AUDIT_USER_LAST_NAME,
USER,
'UPDATE',
SYSDATE,
:new.GORADID_SURROGATE_ID,
:new.GORADID_VERSION,
:new.GORADID_VPDI_CODE);
END;

Try below code for your trigger. Please note that you can use :new and :old only for columns of the table GORADID as you are writing trigger ON GORADID table.
You are selecting USER INTO SZRGORA_AUDIT_USER_BANNER_ID. So you should use SZRGORA_AUDIT_USER_BANNER_ID in your next queries instead of saying USER. Directly saying USERNAME = USER will not work I think.
CREATE OR REPLACE TRIGGER AUDIT_USER.GORADID_UPDT_TRG1
AFTER UPDATE OF GORADID_ADDITIONAL_ID
ON GORADID
FOR EACH ROW
DECLARE
v_SZRGORA_AUDIT_USER_BANNER_ID VARCHAR2(150 CHAR);
v_SZRGORA_AUDIT_STUDENT_BANNER VARCHAR2(9 CHAR);
v_SZRGORA_AUDIT_USER_FIRST_NAME VARCHAR2(150 CHAR);
v_SZRGORA_AUDIT_USER_LAST_NAME VARCHAR2(150 CHAR);
BEGIN
SELECT USER INTO v_SZRGORA_AUDIT_USER_BANNER_ID FROM DUAL;
SELECT SPRIDEN_ID
INTO v_SZRGORA_AUDIT_STUDENT_BANNER
FROM SATURN.SPRIDEN
WHERE SPRIDEN_PIDM = :new.GORADID_PIDM
AND GORADID_ADDITIONAL_ID = :new.GORADID_ADDITIONAL_ID;
SELECT SPRIDEN_FIRST_NAME, SPRIDEN_LAST_NAME
INTO v_SZRGORA_AUDIT_USER_FIRST_NAME, v_SZRGORA_AUDIT_USER_LAST_NAME
FROM SATURN.SPRIDEN
WHERE SPRIDEN_PIDM =
(SELECT PIDM FROM SATURN.IDM_STAFF_AFF_ST
WHERE USERNAME = v_SZRGORA_AUDIT_USER_BANNER_ID);
INSERT INTO AUDIT_USER.SZRGORA_AUDIT VALUES
( v_SZRGORA_AUDIT_STUDENT_BANNER,
:new.GORADID_ADDITIONAL_ID,
:old.GORADID_ADDITIONAL_ID,
v_SZRGORA_AUDIT_USER_FIRST_NAME,
v_SZRGORA_AUDIT_USER_LAST_NAME,
v_SZRGORA_AUDIT_USER_BANNER_ID,
'UPDATE',
SYSDATE,
:new.GORADID_SURROGATE_ID,
:new.GORADID_VERSION,
:new.GORADID_VPDI_CODE);
END;
/

Related

Update of column value within a trigger

Before insert or update of any columns I want to update 1 system column with standard hash MD5 of all table columns, trigger is attached to. My intention is not to tailor this trigger with enumeration of all columns for each trigger and have a function that returns concatenated list of columns per table.
Table DDL:
create table TEST (
id int,
test varchar(100),
"_HASH" varchar(32)
);
Here is my trigger DDL that I would love to work :
CREATE TRIGGER TEST_SYS_HASH_BEFORE_INSERT_OR_UPDATE
BEFORE INSERT OR UPDATE
ON TEST
FOR EACH ROW
DECLARE
var_columns VARCHAR2(10000);
BEGIN
var_columns := FUNC_LISTAGG_EXT(‘TEST');
EXECUTE IMMEDIATE 'SELECT STANDARD_HASH(' || var_columns || ', ''MD5'') from dual'
INTO :new."_HASH";
END;
However this is simply taking headers and set same hash for every row. If I should do this manually , trigger would look like this, what works as I desire, but create it for several tens of tables would be overwhelming
CREATE OR REPLACE TRIGGER TEST_SYS_HASH_BEFORE_INSERT_OR_UPDATE
BEFORE INSERT OR UPDATE
ON TEST
FOR EACH ROW
DECLARE
var_columns VARCHAR(10000);
BEGIN
var_columns := FUNC_LISTAGG_EXT('TEST');
SELECT STANDARD_HASH( :new."ID" || :new."TEST" , 'MD5' )
INTO :new."_HASH";
FROM DUAL;
END;
So my question is whether solution is achievable
Note:
FUNC_LISTAGG_EXT function returns concatenated list of columns from system view

SYS_REFCURSOR is returning all the rows from table without considering the IN parameter

I am facing a weird problem here.
PROCEDURE USL_EMPLOYEEBYID (
EMPLOYEE_ID IN NUMBER,
EMPIDCURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN EMPIDCURSOR FOR
SELECT emp.employee_id,emp.employee_name,emp.present_address,emp.permanent_address,emp.status
FROM Employee_Info emp
WHERE emp.employee_id = EMPLOYEE_ID;
END;
This procedure should give me a single employee upon entering the employee Id. But it is returning all the employees.
What am I doing wrong here?
In your query, Oracle interprets EMPLOYEE_ID as the column EMPLOYEE_ID, not the input parameter, here you find something more; in this way, your where condition is something like a=a.
Change the parameter name to distinguish it from the table column:
PROCEDURE USL_EMPLOYEEBYID (
p_EMPLOYEE_ID IN NUMBER,
po_EMPIDCURSOR OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN po_EMPIDCURSOR FOR
SELECT emp.employee_id,emp.employee_name,emp.present_address,emp.permanent_address,emp.status
FROM Employee_Info emp
WHERE emp.employee_id = p_EMPLOYEE_ID;
END;
this is a good practice, to always know in your code whether you are handling an input parameter, a local variable, a column and so on

Why am I getting this error: "ORA-00922: missing or invalid option" after running a PL/SQL procedure?

I created a table Patient with some attributes, like p_name, p_surname, p_number... I would like to create a procedure to transfer a patient from this table Patient to another table (Patient_backup), case his "p_number" attribute has received an input, deleting it from the first table and remaining only in the second. The second table has the same structure of the first one. I have coded the procedure like that.
CREATE TABLE patient (
p_number VARCHAR2(10) NOT NULL,
p_name VARCHAR2(15),
p_surname VARCHAR2(15),
p_street VARCHAR2(20),
p_city VARCHAR2(15)
);
CREATE TABLE patient_backup (
p_number VARCHAR2(10) NOT NULL,
p_name VARCHAR2(15),
p_surname VARCHAR2(15),
p_street VARCHAR2(20),
p_city VARCHAR2(15)
);
CREATE [OR REPLACE] PROCEDURE transfer (p_number VARCHAR2)
AS
CURSOR k1 IS SELECT p_number FROM patient;
BEGIN
OPEN k1;
LOOP
FETCH k1 INTO p_number;
IF p_number IS NULL THEN
dbms_output.put_line('empty');
ELSE
INSERT INTO patient_backup (SELECT * FROM patient);
Execute Immediate 'Drop Table patient;';
END IF;
END LOOP;
CLOSE k1;
END transfer;
But when I run it,I get the error "ORA-00922: missing or invalid option". Could you help me with that? I wonder if the code is correct. I have read a material about PL/SQL, but the concepts were not connected to each other, so I just tried to gather everything together, and I hope it is correct. Could you help me to correct this code and make it work?
It's hard to tell where exactly the error is, but my guess is: remove the ; from inside the string for execute immediate.
But I think you want do not want to DROP the table - that removes the table completely from the database including all rows and its definition. It won't be accessible after that.
I think what you really want is to DELETE a row from that table, not remove the table completely.
Also: the whole loop is completely unnecessary (and inefficient). You can do that with two simple SQL statements:
insert into patient_backup
select *
from patient
where p_number = 42; --<< to pick one patient
delete from patient
where p_number = 42;
Putting that into a procedure:
CREATE PROCEDURE transfer (p_number_to_delete VARCHAR2)
AS
BEGIN
insert into patient_backup
select *
from patient
where p_number = p_number_to_delete;
delete from patient
where p_number = p_number_to_delete;
END transfer;
It's highly recommended to not use the name of a column as the name of a parameter. That's why I named the parameter p_number_to_delete (but p_number is a bad name for a column that isn't a number to begin with - but that's a different discussion)
I think you need to DECLARE your cursor before you define it.
In Your procedure code have some error
1.P_NUMBER input parameter cannot be used into statment
2.don't use semicolon inside the EXECUTE IMMEDIATE string
3. in loop statement you should use exit otherwise it will run
continuously
Here the code
CREATE OR REPLACE PROCEDURE TRANSFER (P_NUMBER IN VARCHAR2) AS
CURSOR K1 IS
SELECT P_NUMBER FROM PATIENT;
P_NUM PLS_INTEGER;
BEGIN
OPEN K1;
LOOP
FETCH K1 INTO P_NUM;
IF P_NUM IS NULL THEN
DBMS_OUTPUT.PUT_LINE('EMPTY');
ELSE
INSERT INTO PATIENT_BACKUP (SELECT * FROM PATIENT);
DELETE FROM PATIENT;
END IF;
EXIT WHEN P_NUM IS NULL;
END LOOP;
CLOSE K1;
END TRANSFER;

Table name, column names as argument to stored procedure

I am a newbie to stored procedure and to PL/SQL. There is an existing procedure to copy data from one table to another. I want to rewrite the stored procedure to accept table name and column names as arguments.Did googling on the solution but couldn't come up with a solid solution.
Also planning to add column names as argument so that the column names don't have to be repeatedly added in multiple stored procedures which uses the same tables and columns, helps to reduce maintenance when columns names gets added/removed. Code has been added.
Can anyone help me with this? Any sample code will be very helpful.
create or replace procedure copy_data(startDate DATE, endDate DATE,
mainTable varchar2, subTable varchar2, cpyTbl varchar2)
IS
commit_size NUMBER :=1000;
existing_columns NUMBER;
after_deletion_columns NUMBER;
removed_columns NUMBER;
TYPE order_ids IS TABLE OF subTable.id%TYPE INDEX BY PLS_INTEGER;
removable_order_ids order_ids;
bulk_errors EXCEPTION;
PRAGMA EXCEPTION_INIT (bulk_errors, -24381);
CURSOR C1 is select id FROM subTable where ord_id in (select ord_id from
mainTable where tmstmp BETWEEN startDate AND endDate);
BEGIN
open C1;
LOOP
FETCH C1 BULK COLLECT INTO removable_order_ids LIMIT commit_size;
forall indx in 1..removable_order_ids.COUNT
INSERT INTO cpyTbl (id, ord_id, name, phon_nbr)
select id, ord_id, name, phon_nbr from subTable
where ord_id = removable_order_ids(indx) LOG ERRORS INTO
ERR$_cpyTbl('INSERT') REJECT LIMIT UNLIMITED;
COMMIT;
EXIT WHEN removable_order_ids.COUNT < commit_size;
END LOOP;
COMMIT;
end;

how to use date in where clause while inserting values into table using PLSQL store procedure

This is the code i used in stored procedure;
CREATE OR REPLACE PROCEDURE MY_STORE_PROCEDURE (new_date in date)
IS
BEGIN
execute immediate 'INSERT INTO TEMP_1 ( ID CHAR(10),
A_CNT NUMBER,
JOIN_DT DATE,
)
SELECT
L1.ID,
L1.A_CNT,
L1.JOIN_DT,
FROM ACTVY_1 L1
WHERE L1.JOIN_DT = new_date';
END;
===========================================================
Below is the code i used to call store procedure with passing value. value is date which store procedure reciece and used to pull date from a table. but it is giving me error.
DECLARE
a_date DATE;
BEGIN
a_date :=to_DATE ('01-NOV-2013', 'DD-MON-YYYY');
MY_STORE_PROCEDURE(a_date);
END;
Please suggest is there any syntax error or what is issue.
Based on your example, there is no reason to use dynamic SQL. You also have a bunch of errors. Try this:
CREATE OR REPLACE PROCEDURE MY_STORE_PROCEDURE (new_date IN DATE)
IS
BEGIN
INSERT INTO TEMP_1 (ID, A_CNT, JOIN_DT)
SELECT L1.ID, L1.A_CNT, L1.JOIN_DT
FROM ACTVY_1 L1
WHERE L1.JOIN_DT = new_date;
END;

Resources