oracle , sql , trigger - sql

CREATE TRIGGER "CPI"."TRGPRODOFFRPRICE"
AFTER UPDATE or INSERT ON CPI_LOADER_EXEMPTIONS
FOR EACH ROW
DECLARE
table_name varchar(32);
BEGIN
if substr(:new.SID_ID,1,3) = 'POP' then
table_name := 'PROD_OFFR_PRICE_CHARGE';
else
table_name := 'PROD_OFFR_PRICE_ALTERATION';
end if;
execute immediate 'UPDATE :1 set CPI_EXEMPTION=:2 WHERE SID_ID=:3' using table_name, :new.FLAG, :new.SID_ID;
END;
Based on comments i edited into this form, which looks better, but when trying to insert value into table which launches trigger i am getting error 'invalid table name', any idea what is causing this ? wrong tab var declaration possibly?

Try this (real PL/SQL):
CREATE TRIGGER trgSample
AFTER UPDATE or INSERT ON EXEMPTIONS
FOR EACH ROW
DECLARE
sid varchar(10);
sidVal varchar(100);
table_name varchar(32);
flag int;
BEGIN
sid := substr(:new.SID_ID,1,3);
flag := :new.FLAG;
sidVal := :new.SID_ID;
if sid = 'POP' then
table_name := 'PROD_VAL';
else
table_name := 'PROD_VAL2';
end if;
execute immediate 'UPDATE ' || table_name
|| ' set EXEMPTION=sidVal WHERE SID_ID=:x' using sidVal;
END;

AFter all only these changes were neccessary:
'change var to varchar2 for table_name:'
only slight update on execute statement:
'execute immediate 'UPDATE :1 set CPI_EXEMPTION=:2 WHERE SID_ID=:3' using table_name, :new.FLAG, :new.SID_ID;'
thanks for all comments, they ´ve helped me a lot. And need to say a i learn a lot.

Related

How to convert to procedure

I need help in creating this anonymous block into a procedure.
I am new to PLSQL. Any help will be much appreciated. Thank you in advance.
I would like this query to run just by calling a procedure.
TRUNCATE TABLE dblink_status_tbl;
set serveroutput on;
-- or equivalent for your client
declare
-- l_dummy dual.dummy%type;
l_dummy VARCHAR2(20);
l_status VARCHAR2(100);
begin
for r in
(select db_link from all_db_links where db_link in
( 'WP1',
'6P1',
'OP3',
'LP1',
'ODS')
and owner = 'CAMPER')
loop
begin
execute immediate 'select 1 from dual#' || r.db_link into l_dummy;
l_status:= 'ACTIVE';
dbms_output.put_line(r.db_link|| ',' || l_status);
rollback work;
execute immediate 'alter session close database link ' || r.db_link;
exception
when others then
l_status:= sqlerrm;
l_status := replace(replace(l_status,CHR(13), ' '),CHR(10),' ');
l_status := '"' || l_status || '"';
dbms_output.put_line(r.db_link|| ',' || l_status);
end;
insert into dblink_status_tbl
values(r.db_link,l_status);
commit;
end loop;
end;
Basically, you need only the first line in my example:
create or replace procedure p_your_proc as
-- from now on, it is your original code
l_dummy VARCHAR2(20);
l_status VARCHAR2(100);
begin
...
end;
/
Once it is created, run it as
begin
p_your_proc;
end;
/
P.S.
At the beginning, you're truncating a table - if it is necessary within the procedure, you'd use dynamic SQL (as it is a DDL):
begin
execute immediate ('TRUNCATE TABLE dblink_status_tbl');
...
end;
Or, simply delete its contents as
begin
delete from dblink_status_tbl;
...
end;
Make it like something:
create or replace procedure proc_name as
l_dummy VARCHAR2(20);
l_status VARCHAR2(100);
begin
...
Using l_dummy,l_status
end;
And run this like :
"Exec proc_name" or "execute proc_name"

Creating a table if it doesn't exist already

I'm trying to create a table if it doesn't exist already. I'm currently checking to see if it exists in DBA_TABLES first and if that query returns nothing then insert. Is there a way to just check in the same statement so I don't have to break it up into separate queries?
This is what I have currently.
BEGIN
SELECT COUNT(*)
INTO lvnTableExists
FROM DBA_TABLES
WHERE Table_Name = 'SOME_TABLE';
IF lvnTableExists = 0 THEN
EXECUTE IMMEDIATE 'CREATE TABLE SOME_TABLE AS (SELECT * FR0M OTHER_TABLE)';
END IF;
END;
This is something that I'm going for.
DECLARE
sql VARCHAR2(100000);
BEGIN
sql := 'CREATE TABLE SOME_TABLE ' ||
'AS (SELECT * FROM OTHER_TABLE) ' ||
'WHERE NOT EXISTS (SELECT NULL ' ||
'FROM DBA_OBJECTS d WHERE d.Object_Name = 'SOME_TABLE' AND ' ||
'd.Owner = 'SOME_TABLE')';
EXECUTE IMMEDIATE sql;
END;
The problem is that, you can't put a WHERE NOT EXISTS in a CREATE TABLE AS statement.
Yes, that's really a shame that Oracle doesn't have that functionality. I'm sure it will come some day. Until then, if you want to write a PL/SQL wrapper, why not do it like that:
DEClARE
table_exists_already exception;
pragma exception_init(table_exists_already, -955 );
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE SOMETABLE...';
EXCEPTION WHEN table_exists_already THEN
DBMS_OUTPUT.PUT_LINE('Table sometable already exists');
END;
/

Oracle procedure/function to create a trigger in table

I'm trying to create a procedure that given a table name, it will create a sequence and auto incrementing trigger, all using variables based on the table name.
Code :
CREATE OR REPLACE procedure CREATE_SEQUENTIAL_TR(table_name VARCHAR)
is -- Tried using declare but it wouldn't accept
coluna_cod varchar(100 char);
begin
--Finding the cod column name for this table first
--They start with "PK_CD"
select
COLUMN_NAME
into
coluna_cod
from
ALL_TAB_COLUMNS
where
TABLE_NAME=table_name
and COLUMN_NAME like "PK_CD%";
--Creating the sequence obj
drop sequence "cod" || table_name;
create sequence "cod" || table_name;
--Now creating the trigger
create or replace trigger "cod" || table_name || "tr"
before
UPDATE or INSERT on table_name
for each row
declare
cod number := coluna_cod;
tr_name varchar(100 char) := "cod" || table_name
begin
if UPDATING then
if :new.cod != :old.cod then
:new.cod := :old.cod;
end if;
else -- inserting
:new.cod := tr_name.nextval();
end if;
end;
end;
The complexity of this ended up quite out of the scope of my knowledge.
At the moment it is giving an error on drop sequence "cod" || table_name (Unexpected DROP symbol found) but I'm sure I have made other errors.
Can someone help me figure this logic out?
You can't put DDL statements (like drop or create or alter) directly inside a PL/SQL block. If you want to do DDL inside PL/SQL, you can do an execute immediate:
declare
begin
drop sequence X; -- error
execute immediate 'drop sequence X'; -- works fine
end;
/

Dynamic statement in a trigger

I want to run a trigger on Oracle to update several fields of a table with data coming from another table, after an update event. I want to use dynamic SQL statements. Both tables have a lot of fields in common, different by a prefix. The use of "execute immediate" works only if the field I'm updating is explicit. As soon as I use a variable for the field name, it doesn't work. Any idea?
Here is the code :
create or replace TRIGGER AF_UPDATE_PRODUCT_REQUEST
AFTER UPDATE ON PRODUCT_REQUEST
REFERENCING OLD AS OLD NEW AS NEW
FOR EACH ROW
WHEN (old.PREQCOMPLETE=1)
DECLARE
product_fieldname varchar2(100);
counter number(1);
tata number(3);
old_value VARCHAR2(500);
new_value VARCHAR2(500);
BEGIN
tata:=0;
FOR c1 in (SELECT column_name from user_tab_columns WHERE table_name='PRODUCT_REQUEST')
LOOP
old_value:=to_char(:old.PREQDESC2);
new_value:=to_char(:new.PREQDESC2);
IF old_value<>new_value THEN
product_fieldname:=replace(c1.column_name,'PREQ','PU');
select count(*) into counter from user_tab_columns WHERE table_name='PRODUCT' and column_name=product_fieldname;
IF counter=1 THEN
tata:=tata+1;
/*execute immediate 'update product set '|| product_fieldname ||'=:new.'|| c1.column_name ||' where pupname=:old.preqpname';*/
/*execute immediate 'update product set pushelflife=16 where pupname=:d3' using :old.preqpname;*/
IF product_fieldname='PUSHELFLIFE' THEN
/*execute immediate 'update product set pushelflife=:d2 where pupname=:d3' using 15,:old.preqpname;*/
execute immediate 'update product set :d1=:d2 where pupname=:d3' using product_fieldname,15,:old.preqpname;
END IF;
END IF;
END IF;
END LOOP;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
You cannot pass in object or column names as bind variables to a dynamic SQL statement. You would have to construct the dynamic SQL statement using those column names. Something like
execute immediate 'update product ' ||
' set ' || product_fieldname || ' = :val '
' where pupname = :key'
using 15, :old.preqpname

Oracle function dynamic column

I have a function, and I want to determine the name of the column in run time. For this I am passing one variable as an argument, like column_name.
Below is the code with the function:
l_column_name as varchar2(100)
Begin
If(column_name='emp_name')
Then
l_column_name:=EMPLOYEE.EMP_NAME
End If;
begin
select l_column_name from employee
end;
In above code, l_column_name:=EMPLOYEE.EMP_NAME is giving the error
Not allowed in this context.
Any help is much appreicated.
Regards,
Chaitu
As the error says, you can not do this.
You need to look into using the PL/SQL Execute Immediate: http://docs.oracle.com/cd/B14117_01/appdev.101/b10807/13_elems017.htm
declare
l_column_name as varchar2(100);
l_column_results as VARCHAR2(100);
begin
if (column_name = 'emp_name') then
l_column_name := 'EMPLOYEE.EMP_NAME';
end if;
query := 'SELECT ' || l_column_name || ' from employeee';
EXECUTE IMMEDIATE query INTO l_column_results;
end;