Update Multiple Rows in same table after Update using Trigger - sql

If i update ACK or ReJ column it should update all the other columns with the same GlobalID.
create table t_emp(
empid varchar2(10) not null,
empname varchar2(50),
Dep varchar2(50),
ACk number(5),
REJ number(5),
globalID varchar2(10) default '0'
);
insert into t_emp t values ( 'TM01' , 'Logu','Java',null,null,'01');
insert into t_emp t values ( 'BT01' , 'Logu','Java' ,null,null,'01');
insert into t_emp t values ( 'Oracle01' , 'Logu','DBA' ,null,null,'01');
insert into t_emp t values ( 'Google01' , 'Logu','Design' ,null,null,'0');
insert into t_emp t values ( 'AR02' , 'Uthaya','CRM' ,null,null,'02');
insert into t_emp t values ( 'RIL02' , 'Uthaya','Java' ,null,null,'02');
insert into t_emp t values ( 'EA02' , 'Uthaya','DBA' ,null,null,'02');
insert into t_emp t values ( 'TCS02' , 'Uthaya','Java' ,null,null,null);
insert into t_emp t values ( 'P05' , 'Krish','.Net' ,null,null,'05');
insert into t_emp t values ( 'TCS06' , 'Krish','.Net' ,null,null,'06');
insert into t_emp t values ( 'IBM06' , 'Krish','.Net' ,null,null,'06');
CREATE OR REPLACE TRIGGER t_emp_update
AFTER UPDATE
ON t_emp
FOR EACH ROW
DECLARE
t_Ack varchar2(15);
t_Rej varchar2(15);
t_globalID varchar2(10);
t_empid varchar2(10);
BEGIN
t_globalID := :new.globalID;
t_Ack := :new.ACk;
t_Rej := :new.REJ;
t_empid := :new.empid;
IF t_Ack is not null then
DBMS_OUTPUT.PUT_LINE('t_Ack := ' || t_Ack || ', t_globalID := '|| t_globalID ||', t_empid := '||t_empid);
update t_emp set ACk = t_Ack where globalID = t_globalID and empid != t_empid;
end if;
IF t_Rej is not null then
DBMS_OUTPUT.PUT_LINE('t_REJ := ' || t_Rej || ', t_globalID := '|| t_globalID ||', t_empid := '||t_empid);
update t_emp set Rej = t_Rej where globalID = t_globalID and empid != t_empid;
end if;
END;
update t_emp v set Rej = 1 where empid = 'TCS06';
If I Update empid = 'TCS06' it should Update Internally all rows with same globalID (06).
select * from t_emp order by empname,globalID;
I am getting some errors in this trigger.
ORA-04091: table TEST1.T_EMP is mutating, trigger/function may not see it
ORA-06512: at "TEST1.T_EMP_UPDATE", line 17
ORA-04088: error during execution of trigger 'TEST1.T_EMP_UPDATE'
Kindly Help me ...

This link and this other one should be helpfull to understand the error and how to correct it. Also check sample of an AFTER UPDATE trigger.
Check a similar question here at SO with a detailed answer.

Please refer these links:
INSERT trigger for inserting record in same table(Stackoverflow)
Avoiding Mutating Tables

Related

Error(20,56): PLS-00049: bad bind variable 'NEW.NEW_NAME'

I am facing this error while creating a trigger.
error - Error(20,56): PLS-00049: bad bind variable 'NEW.NEW_NAME'
if anyone can help it will be appreciated.
Please refer to my code below
Thanks in Advance :)
CREATE OR REPLACE TRIGGER insert_update_delete_employees AFTER
INSERT OR UPDATE OR DELETE ON employees
REFERENCING
OLD AS old
NEW AS new
FOR EACH ROW
ENABLE DECLARE
v_user VARCHAR2(20);
v_count NUMBER;
v_date VARCHAR2(20);
BEGIN
SELECT
user,
to_date(sysdate, 'DD/MON/YYYY HH24:MI:SS')
INTO
v_user,
v_date
FROM
dual;
SELECT
COUNT(1)
INTO v_count
FROM
employees;
IF updating THEN
INSERT INTO audit_table (
table_name,
user_name,
event,
event_date,
table_count,
new_object_name,
old_object_name
) VALUES (
'EMPLOYEES',
v_user,
'UPDATE',
v_date,
v_count,
:new.new_name,
NULL
);
dbms_output.put_line('Table data has been update by user ' || v_user);
SELECT
COUNT(*)
INTO v_count
FROM
employees;
ELSIF inserting THEN
INSERT INTO audit_table (
table_name,
user_name,
event,
event_date,
table_count,
new_object_name,
old_object_name
) VALUES (
'EMPLOYEES',
v_user,
'INSERT',
v_date,
v_count,
:new.new_name,
:old.old_name
);
dbms_output.put_line('Table data has been inserted by user ' || v_user);
SELECT
COUNT(*)
INTO v_count
FROM
employees;
ELSIF deleting THEN
INSERT INTO audit_table (
table_name,
user_name,
event,
event_date,
table_count,
new_object_name,
old_object_name
) VALUES (
'EMPLOYEES',
v_user,
'DELETE',
v_date,
v_count,
NULL,
:old.old_name
);
dbms_output.put_line('Table data has been deleted by user ' || v_user);
SELECT
COUNT(*)
INTO v_count
FROM
employees;`enter code here`
END IF;
END;
As you are using sample database schema, So please use :new.first_name column instead of :new.new_name

Dynamic PL-SQL programming - Issue with DBMS_SQL.PARSE

I wrote a query to fetch the details using some business logic. However, I got stuck at the below line
DBMS_SQL.PARSE(CUR, SQLSTR, DBMS_SQL.NATIVE);
And I got the below error. I checked the syntax again and again and it is perfectly fine. So, could you guys help me in fixing this? Errors below.
ORA-00933: SQL command not properly ended
ORA-06512: at "SYS.DBMS_SQL", line 1134
ORA-06512: at line 35
0093.00000 - "SQL command not properly ended"
Code is below.
DECLARE
SQLSTR VARCHAR2(30000);
CUR INTEGER;
SER INTEGER;
WS VARCHAR2(10);
REFCUR SYS_REFCURSOR;
TYPE ERMAS IS TABLE OF DUAL%ROWTYPE;
SERULT ERMAS;
VAL MRUL.OWL%TYPE;
CURSOR TION IS
SELECT RUD.COL, RUD.VAL, RUD.OPR, RUD.RU3
FROM RMAP RUM, RDET RUD
WHERE RUM.RU3 = RUD.RU3
AND RUD.RU3 IN ('60', '61', '62');
BEGIN
CUR := DBMS_SQL.OPEN_CURSOR;
SQLSTR := 'SELECT * '||CHR(13);
SQLSTR := SQLSTR || 'FROM DUAL '||CHR(13);
SQLSTR := SQLSTR || 'WHERE MRUL = : OWL AND (';
FOR DONC IN TION
LOOP
SQLSTR := SQLSTR || DONC.COL || DONC.OPR||':'|| DONC. RU3 ||'OR ';
END LOOP;
SQLSTR := REGEXP_REPLACE(SQLSTR, 'OR ', ')');
DBMS_SQL.PARSE(CUR, SQLSTR, DBMS_SQL.NATIVE);
SELECT OWL
INTO VAL
FROM MRUL
WHERE RU2 = '20';
DBMS_SQL.BIND_VARIABLE(CUR, ':OWL', WS);
FOR DONC IN TION
LOOP
DBMS_SQL.BIND_VARIABLE(CUR, ':'|| DONC.RU3, DONC. VAL);
END LOOP;
SER := DBMS_SQL.EXECUTE(CUR);
REFCUR := DBMS_SQL.TO_REFCURSOR(CUR);
FETCH REFCUR BULK COLLECT INTO SERULT;
END;
Updating the create and insert queries.
CREATE TABLE RDET
(
COL VARCHAR2(50) NOT NULL,
VAL VARCHAR2(50) NOT NULL,
OPR VARCHAR2(50) NOT NULL,
RU3 VARCHAR2(50) NOT NULL
);
CREATE TABLE RMAP
(
RU2 VARCHAR2(50) NOT NULL,
RU3 VARCHAR2(50) NOT NULL
);
CREATE TABLE MRUL
(
OWL VARCHAR2(50) NOT NULL,
RU2 VARCHAR2(50) NOT NULL
);
INSERT INTO RDET
VALUES (‘DELHI’, ‘CITY’, ‘=’, ‘60’);
INSERT INTO RDET
VALUES (‘SHIMLA’, ‘VILLAGE’, ‘<>’, ‘61’);
INSERT INTO RDET
VALUES (‘NOIDA’, ‘TOWN’, ‘=’, ‘62’);
INSERT INTO RMAP
VALUES (‘20’, ‘60’);
INSERT INTO RMAP
VALUES (‘21’, ‘61’);
INSERT INTO RMAP
VALUES (‘21’, ‘62’);
INSERT INTO MRUL
VALUES (‘COUNTRY’, ‘20’);
INSERT INTO MRUL
VALUES (‘CONTINENT, ‘21’);
INSERT INTO MRUL
VALUES (‘AREA’, ‘22’);
INSERT INTO MRUL
VALUES (‘AREA’, ‘23’);
The issue was that the SQL statement was incorrectly suffixed with 'OR'. So, did an RTRIM to remove it and the procedure worked.

oracle sql : "get or insert" stored procedure

I would like to do a stored procedure that receive an input param and then
if targeted table does not contains that value, a new row is created and then the id of the created row is returned
if targeted table already contain input param, the id of the row is returned
For moment I only manage to insert new row only if input param is new:
--exemple of table with a primary id a column with value
create table unique_number_table (
id NUMBER(12) not null,
UNIQUE_NUMBER VARCHAR2(80) not null,
constraint PK_ID primary key (ID)
);
create sequence SEQ_NUMBER
INCREMENT BY 1
START WITH 2
MAXVALUE 999999999
MINVALUE 0;
create or replace procedure insert_or_get_unique_number ( input_number in varchar ) is
begin
insert into unique_number_table (id, UNIQUE_NUMBER)
select SEQ_NUMBER.NEXTVAL ,input_number
from dual
where not exists(select * from unique_number_table
where UNIQUE_NUMBER =input_number);
end insert_or_get_unique_number;
Do you know how to do this?
Seems to me like you want a stored function and not a procedure.
create or replace function insert_or_get_unique_number (input_number varchar2)
return UNIQUE_NUMBER_TABLE.ID%type
is
L_NUM UNIQUE_NUMBER_TABLE.ID%type;
begin
select ID
into L_NUM
from UNIQUE_NUMBER_TABLE
where UNIQUE_NUMBER = input_number;
return L_NUM;
exception
when NO_DATA_FOUND then
insert into unique_number_table (id, UNIQUE_NUMBER)
values (SEQ_NUMBER.NEXTVAL, input_number)
returning ID into L_NUM;
return L_NUM;
end insert_or_get_unique_number;
This is a possible solution to your problem.
CREATE OR REPLACE PROCEDURE insert_or_get_unique_number (
input_number IN VARCHAR,
c_out out sys_refcursor
) IS
Lv_input_exists INT;
lv_myRowid VARCHAR2(200);
err_code varchar2(600);
err_msg varchar2(500);
BEGIN
--step 1 check if the input param exists. -
select count(*)
INTO Lv_input_exists
FROM unique_number_table
WHERE unique_number = input_number;
--step 2 if it exists than get the rowid of that row and return that value
IF Lv_input_exists > 0
THEN
OPEN c_out for
SELECT ROWID
FROM unique_number_table Uni
WHERE uni.id = input_number ;
RETURN;
ELSE
-- STEP 3 the input number does not exists therefore we need to insert and return the rowid--
INSERT INTO unique_number_table (
id,
unique_number
)
VALUES(
seq_number.NEXTVAL,
input_number)
returning ROWID into lv_myRowid;
----STEP 4 Open the cursor and return get the rowid.
OPEN c_out for
SELECT lv_myRowid
FROM DUAL ;
SYS.dbms_output.put_line( 'Done' );
END IF;
EXCEPTION WHEN OTHERS THEN
err_code := SQLCODE;
err_msg := SUBSTR(SQLERRM, 1, 200);
SYS.dbms_output.put_line( err_code || ' '||': '||err_msg );
END insert_or_get_unique_number;
you can test the procedure like so.
set serveroutput on ;
DECLARE
INPUT_NUMBER VARCHAR2(200);
C_OUT sys_refcursor;
BEGIN
INPUT_NUMBER := '3';
INSERT_OR_GET_UNIQUE_NUMBER(
INPUT_NUMBER => INPUT_NUMBER,
C_OUT => C_OUT
);
DBMS_SQL.return_result(C_OUT);
END;

Trying to print via a table of records

I'm trying to print using a table of records. The original table looks as follows:
CREATE TABLE dept1
( DEPTNO NUMBER(3) PRIMARY KEY,
DNAME VARCHAR2(20),
LOC VARCHAR2(20)
);
Dept = {(10, 'ACCOUNTING', 'NEW YORK'),
(20, 'RESEARCH', 'DALLAS'),
(30, 'SALES', 'CHICAGO'),
(40, 'OPERATIONS', 'DALLAS'),
(50, 'MARKETING', 'BOSTON')}
What I think I'm doing with this code is creating a procedure print_deptlist that will print all the records from the record deptlist that I created: We're required to use that method
CREATE OR REPLACE PROCEDURE print_deptlist IS
deptlist dept1%rowtype;
Begin
Select * into deptlist from dept1;
DBMS_OUTPUT.PUT_LINE(DEPTLIST.deptno || ',' || deptlist.dname || ',' || deptlist.loc);
end;
/
See above...
I'm expecting results that looks lists the column names with the records below:
You can use such a loop statement through
BULK COLLECT which is SELECT statements that retrieve multiple rows with a single fetch, also improving the speed of data retrieval
SQL> SET SERVEROUTPUT ON
SQL> CREATE OR REPLACE PROCEDURE print_deptlist IS
TYPE tab_dept IS TABLE OF dept1%rowtype;
deptlist tab_dept;
BEGIN
SELECT * BULK COLLECT INTO deptlist FROM dept1;
FOR i IN 1..deptlist.count
LOOP
dbms_output.put_line(deptlist(i).deptno || ',' || deptlist(i).dname
|| ',' || deptlist(i).loc);
END LOOP;
END;
/
Demo

Dynamic PL/SQL query, how to ignore null parameters?

I have a PL/SQL procedure with multiple parameters. When a webapp calls the procedure, if it's not using a certain parameter, it passes is as null, ie
procedure test (param1 in varchar2, param2 in varchar2, param3 in varchar2, cursor out sys_refcursor)
...
end procedure test;
I want to make an SQL query where I include the given parameters in the WHERE clause only if the parameter is not null. Is there a way to achieve this in an elegant way, other than building the SQL query in a string and then opening the cursor for that string, like this
vSQL := 'SELECT * from TABLE WHERE something = something_else';
if param1 IS NOT NULL
vSQL := vSQL || 'AND some_param = ' || param1;
I have answered a similar question on dba.stackexchange.com
You can code it all into a single select
SELECT * from TABLE WHERE something = something_else
AND ((param1 IS NOT NULL AND some_param = param1) OR 1)
Create a test table:
create table testtab
(
name_first varchar2(50),
name_last varchar2(50),
name_middle varchar2(50)
);
insert into testtab values ('Joe', 'Jones', 'A');
insert into testtab values ('Joe', 'Smith', 'A');
insert into testtab values ('Steve', 'Jones', 'B');
insert into testtab values ('Axl', 'Rose', 'C');
insert into testtab values ('Phil', 'McCracken', 'D');
commit;
Create your procedure:
CREATE OR REPLACE procedure ECDATA.get_testtab_rows
(i_name_first in varchar2 default null,
i_name_last in varchar2 default null,
i_name_middle in varchar2 default null,
o_cursor out sys_refcursor
) as
v_result_cur sys_refcursor;
begin
open v_result_cur for
select * from testtab
where name_first like nvl(i_name_first, '%')
and name_last like nvl(i_name_last, '%')
and name_middle like nvl(i_name_middle, '%')
;
o_cursor := v_result_cur;
end;
/
Then call it like this:
declare
v_cur sys_refcursor;
testtab_rec testtab%rowtype;
begin
get_testtab_rows(i_name_last=>'Jones', o_cursor=>v_cur);
loop
fetch v_cur into testtab_rec;
exit when v_cur%notfound;
dbms_output.put_line(testtab_rec.name_first || ' ' || testtab_rec.name_middle || ' ' || testtab_rec.name_last);
end loop;
exception
when others then raise;
end;