Oracle trigger keywoard :new not found - oracle

my Oracle SqlDeveloper (or Oracle Database?) doesn't know the :NEW keyword.
For instance, if I enter the following sample from Oracles website,
when I execute the "create or replace trigger" paragraph, a window "Enter bind variable" pops up and asks for the bind variable ":new".
Shouldn't this ":new" variable be predefined?
(Oracle SQL Developer 4.0.1.14, Oracle DB 11gR2, Windows)
drop table tab1;
create table tab1 (c1 clob);
insert into tab1 values ('testtext');
create or replace trigger trg1
before update on tab1
for each row
begin
dbms_output.put_line('Old value of CLOB column: '||:OLD.c1);
dbms_output.put_line('Proposed new value of CLOB column: '||:NEW.c1);
-- Previously, we couldn't change the new value for a LOB.
-- Now, we can replace it, or construct a new value using SUBSTR, INSTR...
-- operations for a CLOB, or DBMS_LOB calls for a BLOB.
:NEW.c1 := :NEW.c1 || to_clob('<hr><p>Standard footer paragraph.');
dbms_output.put_line('Final value of CLOB column: '||:NEW.c1);
end;
/
set serveroutput on;
update tab1 set c1 = '<h1>Different Document Fragment</h1><p>Different text.';
select * from tab1;

It turned out I just had to press "Apply" in the Bind dialog, and the trigger was created. Obviously a bug in SqlDeveloper. At least there is a workaround...

I added the 'REFERENCING' statement, and tested the code, seems to work just fine--- BTW, you can just turn DBMS output on in SQL dev w/o having to run the command..
CREATE OR REPLACE TRIGGER trg1
BEFORE UPDATE
ON tab1
REFERENCING NEW AS new OLD AS old
FOR EACH ROW
BEGIN
DBMS_OUTPUT.put_line ('Old value of CLOB column: ' || :old.c1);
DBMS_OUTPUT.put_line ('Proposed new value of CLOB column: ' || :new.c1);
-- Previously, we couldn't change the new value for a LOB.
-- Now, we can replace it, or construct a new value using SUBSTR, INSTR...
-- operations for a CLOB, or DBMS_LOB calls for a BLOB.
:new.c1 := :new.c1 || TO_CLOB ('<hr><p>Standard footer paragraph.');
DBMS_OUTPUT.put_line ('Final value of CLOB column: ' || :new.c1);
END;

Related

Oracle to PostgreSQL translate

I am migrating Oracle DLL to PostgreSQL, I am having an issue translate the following piece of code to PostgreSQL
-- Generate ID using sequence and trigger
CREATE SEQUENCE partner_seq START WITH 1 INCREMENT BY 1;
CREATE OR REPLACE TRIGGER partner_seq_tr
BEFORE INSERT ON partner FOR EACH ROW
WHEN (NEW.idPartner IS NULL)
BEGIN
SELECT partner_seq.NEXTVAL INTO :NEW.idPartner FROM DUAL;
END;
/
-- CREATE UNIQUE INDEX partner_idxName ON partner (Name);
-- COMMIT;
You don't actually need a trigger in Postgres for that. Simply declare the column as
idpartner integer generated always as identity
And Postgres will use the (automatically created) sequence automatically if the column is not specified as a target column in the INSERT statement.
Alternatively, if you really want a trigger:
create sequence partner_seq;
create function assign_partner_id()
returns trigger
as
$$
begin
if new.idpartner is null then
new.idpartner := nextval('partner_seq');
end if;
return new;
end;
$$
language plpgsql;
create trigger partner_seq_trg
before on partner insert on each row
execute procedure assign_partner_id();

I want to make this procedure on Oracle SQL

I want to make this procedure on Oracle SQL:
CREATE OR REPLACE PROCEDURE STS_OWNER.PRC_CAMBIO_LDC1 IS
CURSOR LDC1 IS
select CASE_NO
from ldc_cases
where case_no in (select barcode
from sts_tracking
where ldc='0'
and duplicated='0');
FOR UPDATE BARCODE;
BARCODE VARCHAR2(50);
BEGIN
OPEN LDC1;
FETCH LDC1 INTO BARCODE;
WHILE LDC1%FOUND LOOP
update sts_tracking
set ldc= 1
WHERE CURRENT LDC1;
FETCH LDC1 INTO BARCODE;
END LOOP;
CLOSE LDC1;
COMMIT;
END;
There is no need for use loop for updating table. Cursor contains only one value (or rather should because you are fetching it into varchar variable).
What type is case_no in ldc_cases? should be varchar.
Kindly format your code ,you can use either Oracle toad client or SQL developer to create and Format a Stored Proc .Below is the syntax of the same.
CREATE [OR REPLACE] PROCEDURE procedure_name
[ (parameter [,parameter]) ]
IS
[declaration_section]
BEGIN
executable_section
[EXCEPTION
exception_section]
END [procedure_name];

Bind variable in SQL Developer with Oracle 11g

I have problem when trying to excute a sequence with a before insert trigger.
CREATE TABLE personne (ID number, nom varchar2(250 char));
CREATE SEQUENCE s_inc_pers START WITH 1 INCREMENT BY 1;
CREATE TRIGGER tr_inc_pers ON t1 BEFORE INSERT
FOR EACH ROW
DECLARE
BEGIN
select s_inc_pers into :new.t1.ID from DUAL;
END.
Oracle reports a bad bind variable if you try to reference something with :NEW that is not a column in the target table. In this case it may be prompting you for a bind value as the statement is malformed.
The NEW pseudorecord refers to the row in the triggering table that is being affected by the statement. You don't need to (and mustn't) include the table name when you use the pseudorecord field, so :new.t1.ID should just be :new.ID.
To get the next value from the sequence you need to use nextval, you can't only provide the sequence name.
Your clauses are also in the wrong order, you need the DML event (insert) befroe the target table.
CREATE TRIGGER tr_inc_pers BEFORE INSERT ON t1
FOR EACH ROW
BEGIN
select s_inc_pers.nextval into :new.ID from DUAL;
END;
As you are using 11g you don't even need to select from dual, you can just assign the column value:
CREATE TRIGGER tr_inc_pers BEFORE INSERT ON t1
FOR EACH ROW
BEGIN
:new.ID := s_inc_pers.nextval;
END;

How do I convert row into CLOB in the applied trigger after update?

The idea is, I want to clone the record as a CLOB when it is updated.
Why do it in such a way?
There are two different applications A1 and A2, A1 is depended on by A2.
Based on A1 values, calculations are made for values for A2.
The A2 process runs just once per day to calculate the values, but for A1 every field in the TABLE_NAME in question can be altered several times a day and doesn't have a history.
The aim is to create a history which is a CLOB field in a table "NEW_TABLE" of automatic form.
Sorry for my English, but if something is not understandable I can rewrite the question
My Code Here:
CREATE or REPLACE TRIGGER TRIGGER_NAME
AFTER UPDATE
ON TABLE_NAME
FOR EACH ROW
DECLARE
row_record NEW_TABLE%rowtype;
c_xml CLOB;
FUNCTION GetXML(a_tablela varchar2, a_key_1 varchar2, a_key_2 varchar2)
RETURN CLOB
is
x_xml CLOB;
BEGIN
select dbms_xmlgen.getxml('select * from '||a_tablela||' where key_1 = '''||a_key_1||''' and key_2 = '''||a_key_2||'''') into x_xml from dual;
return x_xml;
END;
BEGIN
--** TABLE_NAME Automatically fetches all columns and transforms them to CLOB
c_xml := GetXML('TABLE_NAME', :new.key_1, :new.key_2);
if c_xml is not null then
row_record.TABLE_NAME :=c_xml;
end if;
INSERT INTO NEW_TABLE VALUES row_record;
EXCEPTION
when others then
raise_application_error(-20000,'ERROR: '||to_char(sqlcode));
END;
Now I get error:
ORA-04091: table TABLE_NAME is mutating, trigger/function may not see it.
when I get this record across SELECT statement.
How do I convert row into CLOB in the applied TRIGGER AFTER UPDATE ?
Thanks.
The reason you can't use a select statement is because you're in the trigger, and the table is changing, or 'mutating', as the error says. The only way you can get the data from the row that's being updated here is using new and old:
old.column1
new.column1
Old being the value of the column before the update, new being the value after the update.
Example:
CREATE or REPLACE TRIGGER TRIGGER_NAME
AFTER UPDATE
ON TABLE_NAME
FOR EACH ROW
BEGIN
l_string := 'This is the old value for column 1: ' || old.column1 || '. This is the new value: ' || new.column1;
dbms_output.put_line(l_string);
END;
You won't be able to use dbms_xmlgen because it uses a select statement, which throws the mutating error exception.
I'm not sure I perfectly understand what you're trying to do, but you should be able to build the CLOB yourself just by concatenating yourself with the column names. Like this:
CREATE or REPLACE TRIGGER TRIGGER_NAME
AFTER UPDATE
ON TABLE_NAME
FOR EACH ROW
BEGIN
l_clob := 'Column1 ' || old.column1 || ', Column2 ' || old.column2; --For as many columns as are in the table
--Now you have a clob with all the old values, insert it where you want it
END;
And then go from there. If you really want the XML format you can do that yourself as well, just concatenate the strings together.

No Data Found Error in Oracle

I'm trying to insert a data into oracle database(version 11g xe).But when i'm trying to execute the procedure using toad i'm getting the error as 'ORA-01403: no data found'.
Here's my code
CREATE OR REPLACE PROCEDURE ACTSINFO.sp_Insert_WorkDetails
(p_workname IN varchar ,
p_workaddress IN varchar)
IS
BEGIN
insert into workdetails (workname,workaddress) values (p_workname,p_workaddress);
END sp_Insert_WorkDetails;
I tried to execute the procedure using the below statememt
EXEC sp_Insert_WorkDetails('test','test');
Also i've defined a trigger and sequence for the autoincrement of workdetailsid in table workdetails
Sequence is as follows
ALTER SEQUENCE ACTSINFO.WORKDETAILS_WORKID_SEQ
INCREMENT BY 1
MINVALUE 0
MAXVALUE 9999999999999999999999999999
NOCACHE
NOCYCLE
NOORDER
Trigger is as follows
DROP TRIGGER ACTSINFO.WORKDETAILS_INSERT;
CREATE OR REPLACE TRIGGER ACTSINFO.WORKDETAILS_INSERT
BEFORE INSERT
ON ACTSINFO.WORKDETAILS
REFERENCING NEW AS New OLD AS Old
FOR EACH ROW
BEGIN
SELECT WORKDETAILS_WORKID_SEQ.NEXTVAL INTO :NEW.WORKID FROM WORKDETAILS;
END;
I'm new to oracle.Pls help me...
Your trigger is the problem:
SELECT WORKDETAILS_WORKID_SEQ.NEXTVAL INTO :NEW.WORKID FROM WORKDETAILS;
If there are no rows in workdetails the select will return nothing. Even worse, if your workdetails table has more than one row this will also fail miserably.
You really want the following:
SELECT WORKDETAILS_WORKID_SEQ.NEXTVAL INTO :NEW.WORKID FROM dual;
or - if you are on 11g - then you can use:
:NEW.WORKID := WORKDETAILS_WORKID_SEQ.NEXTVAL;

Resources