Trigger update with if condition - if-statement

create or replace
TRIGGER TR_SITECONTACT_UPDATE
AFTER UPDATE OR INSERT ON s_ct
FOR EACH ROW
DECLARE
v_SID s_ct.sid%type;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF :NEW.CTID != :OLD.CTID THEN
UPDATE CT
SET lastupdatedon =sysdate,
LASTUPDATESITE=:NEW.SID
WHERE CTID = :NEW.CTID;
COMMIT;
END IF;
END;
Here it's possible to check whether lastupdatedCOF is null or not then use update statement, before update row i need to check lastupdatedCOF IS NULL OR NOT in CT Table. IF Null means i need to use below update statement
UPDATE CT
SET lastupdatedon =sysdate,
LASTUPDATESITE=:NEW.SID
WHERE CTID = :NEW.CTID;
COMMIT;
lastupdatedCOF IS NOT NULL Means
UPDATE CT
SET lastupdatedon =sysdate,
LASTUPDATESITE=:NEW.SID,
lastupdatedCOF = NULL
WHERE CTID = :NEW.CTID;
COMMIT;

If I read your question, either lastupdatedCOF is null (in which case, it remains null) or lastupdated_cof is not null and you want to set it to null.
So, why not just always set it to null?
I.e.:
create or replace
TRIGGER TR_SITECONTACT_UPDATE
AFTER UPDATE OR INSERT ON s_ct
FOR EACH ROW
DECLARE
v_SID s_ct.sid%type;
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF :NEW.CTID != :OLD.CTID THEN
UPDATE CT
SET lastupdatedon =sysdate,
LASTUPDATESITE=:NEW.SID,
lastupdatedCOF = NULL
WHERE CTID = :NEW.CTID;
COMMIT;
END IF;
END;
One other point - do you really, really need an autonomous transaction? What if the transaction inserting into/updating the s_ct table is rolled back - as things stand, you'd be left with a row in the CT table that's been changed, despite the underlying change not having taken place.

Related

How to use page item value inside a trigger query in oracle?

I want the following trigger to be run correctly but it rise an error which is: bad bind variable 'P23_ID'.
The trigger query is:
Create or replace trigger "newTRG"
Before
Insert on "my_table"
For each row
Begin
If :new."ID" is null then
Insert into my_table (ID) values (:P23_ID);
end if;
End;
Use the v() syntax:
create or replace trigger "newTRG" before
insert on "my_table"
for each row
begin
if :new."ID" is null then
insert into my_table ( id ) values (v('P23_ID'));
end if;
end;
On a side note, if this is a primary key value it is a lot easier to use identity columns (the new way) or a sequence (the old way) to populate your column. Doing this from a page item is error prone.

Oracle APEX: NO DATA FOUND when querying the APEX_COLLECTION

I am querying APEX_COLLECTION view to see if a record exists and when it does not, I am getting NO_DATA_FOUND exception. To handle that I used an anonymous block:
BEGIN
SELECT c001, c002 INTO l_var1, l_var2
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
EXCEPTION
WHEN NO_DATA_FOUND
l_var1 := NULL;
l_var2 := NULL;
END;
Is there a better way to handle this?
If you just want to see if a record exists, you can use de COUNT() function. In this way, it is not necessary to use anonymous blocks or NO_DATA_FOUND excepcion. The COUNT function always returns a value.
SELECT COUNT(*)
INTO l_count
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
IF l_count > 0 THEN
-- Do something, the record exits
ELSE
-- Do something, the record does not exit
END IF;
Did not find better solution to my issue besides using anonymous block and capturing a NO_DATA_FOUND exception.
Use a predefined cursor and you won't be bothered with the NO_DATA_FOUND exception.
DECLARE
cursor c_apex_coll
is
SELECT c001, c002
FROM APEX_COLLECTION
WHERE collection_name = 'TEST' AND c003='test';
l_var1 varchar2(256);
l_var2 varchar2(256);
BEGIN
open c_apex_coll;
fetch c_apex_coll into l_var1, l_var2;
close c_apex_coll;
END;

IF statement doesn't allow Select statement to compare the given string

Write a procedure (oracle plsql) to do any one of the following: (a) update the table course and set the fee of the input course name equal to fee of java course. (b) insert a new row for given input course and set the fee lowest of all courses available in the table. Condition is: do (a) if the input course name is already present in the table otherwise do (b) if the input course name is not in the table.
I am providing here the basic details of table:
create table course(cid number primary key, cname varchar2(100), duration number, fee number);
insert into course (CID, CNAME, DURATION, FEE)
values (101, 'java', 30, 13000);
insert into course (CID, CNAME, DURATION, FEE)
values (102, 'c', 20, 5000);
insert into course (CID, CNAME, DURATION, FEE)
values (104, 'oracle', 20, 20000);
insert into course (CID, CNAME, DURATION, FEE)
values (105, 'python', 20, 30000);
insert into course (CID, CNAME, DURATION, FEE)
values (106, 'sql', 20, 1000);
I tried the below code but i don't know how to compare the given name for each rows in the table inside IF statement. Please take a look in the code and help me.
create or replace procedure proc_CourseFeeUpdateTry(coursename in course.cname%type,
java_fee out number) is
n_fee number;
j_fee number;
begin
if course.cname = coursename then --i'm getting error here
select t.fee into j_fee from course t where t.cname = 'java';
java_fee := j_fee;
update course t set t.fee = java_fee where t.cname = coursename;
dbms_output.put_line('new course added');
else
dbms_output.put_line(sqlerrm || '-' || sqlcode);
select min(t.fee) into n_fee from course t;
java_fee := n_fee;
insert into course values (103, coursename, 40, java_fee);
end if;
commit;
end;
The error you get seems to flow from a major misconception of available table data to procedure. An IF statement has no problem allowing subsequent selects. The problem here is you referenced a table column (course.cname) without having previously select anything from the course table. Just because a table exists does not give access to the data within it, you must select before referencing column values. So before that IF at you need at least a select and since it's a procedure a Select .. into specifically.
Now a select into makes column values available if it exist but if not it throws NO_DATA_FOUND exception. We this fact to avoid that IF entirely. Further there are 2 instances where you use the structure:
select data_value into local variable;
output_variable = local_variable;
This is not necessary as you can just select directly into the output_variable.
The following contains 2 revisions to your procedure. The 1st leaving your code as is as much as possible. The 2nd revising the code to make use of all the above mentioned. I hope this helps you understand further.
The minimum necessary change requires you to select the course table prior to your IF statement and handle the no_data_found_error.
create or replace procedure proc_CourseFeeUpdateTry(coursename in course.cname%type,
java_fee out number) is
n_fee number;
j_fee number;
l_course_name course.cname%type;
begin
begin
select c.cname
into l_course_name
from course c
where c.cname = coursename;
exception
when no_data_found then
null;
end ;
if l_course_name = coursename then
select t.fee into j_fee from course t where t.cname = 'java';
java_fee := j_fee;
update course t set t.fee = java_fee where t.cname = coursename;
dbms_output.put_line('course fee updated'); --- course was not added just updted
else
dbms_output.put_line(sqlerrm || '-' || sqlcode);
select min(t.fee) into n_fee from course t;
java_fee := n_fee;
insert into course values (103, coursename, 40, java_fee); --- leave message
dbms_output.put_line('new course added');
end if;
commit;
end;
The second version uses the above mentions topics and restructures.
create or replace procedure proc_CourseFeeUpdateTry(coursename in course.cname%type,
java_fee out number) is
l_cid course.cid%type;
begin
select c.cid
into l_cid
from course c
where c.cname = coursename;
begin -- inner block to trap java not found
-- if we get here then we know that the implied test cource.cname = coursename is true
select t.fee into java_fee
from course t where t.cname = 'java';
update course t set t.fee = java_fee where cid = l_cid;
dbms_output.put_line( coursename || ' fee updated');
commit;
exception
when no_data_found then
raise_application_error( -20109, 'course name ''java'' is not in course table');
end ; -- inner block
exception
when no_data_found then
-- if we get here the we know that the course name does not exist
select min(t.fee) into java_fee from course t;
insert into course values (103, coursename, 40, java_fee);
commit;
end;
Notice the insert in both procedures. It hard codes id. As a result your procedure is able to add a row exactly 1 time. This is an extremely poor process. Either pass the new id as a parameter (still not good, but better), or redefine the table to auto generate the key. Depending on your version of Oracle look up sequences and insert triggers (prior to 12c) or Identity Columns (12c and later).

Storing unique values in django hstorefield with postgresql

Is it possible to add a postgresql hstorefield (django >= 1.8) to a model where values in the hstore are unique?
Keys are obviously unique but can values be unique as well? I suppose custom validators could be added to the model but I am curious to know if this can be done on the database level
A single hstore value can contain multiple key => value pairs, making a solution based on a unique index impossible. Additionally, your new hstore value can also have multiple key => value pairs. The only viable alternative is then a BEFORE INSERT OR UPDATE trigger on the table:
CREATE FUNCTION trf_uniq_hstore_values() RETURNS trigger AS $$
DECLARE
dups text;
BEGIN
SELECT string_agg(x, ',') INTO dups
FROM (SELECT svals(hstorefield) AS x FROM my_table) sub
JOIN (SELECT svals(NEW.hstorefield) AS x) vals USING (x);
IF dups IS NOT NULL THEN
RAISE NOTICE format('Value(s) %s violate(s) uniqueness constraint. Operation aborted.', dups);
RETURN NULL;
ELSE
RETURN NEW;
END IF;
END; $$ LANGUAGE plpgsql;
CREATE TRIGGER tr_uniq_hstore_values
BEFORE INSERT OR UPDATE ON my_table
FOR EACH ROW EXECUTE PROCEDURE trf_uniq_hstore_values();
Note that this will not trap existing duplicates in the table.

Transaction in SP avoid correct answer

I have an SP that work very well when called from SSMS. but when I call it from my application
that written in native C++ and use ODBC for connecting to database, the operation return no error but actually do nothing in the database.
My SP read some values from some temporary tables and either insert them in database or update them.
I had a transaction in SP that guard all the code of SP, I hardly debug my SP and find that function will return in first insert or update and so do nothing. So I remove that transaction and function partly worked, I mean it add some of the items but leave some of them there without adding them to the database.
here is a skeleton of my SP:
--BEGIN TRANSACTION
DECLARE #id bigint, #name nvarchar(50)
DELETE FROM MyTable WHERE NOT( id IN (SELECT id from #MyTable) )
DECLARE cur1 CURSOR FOR SELECT id, name FROM #MyTable
OPEN cur1
WHILE 1 != 0
BEGIN
FETCH cur1 INTO #id, #name
IF ##FETCH_STATUS != 0 BREAK;
UPDATE MyTable SET [Name]=#name WHERE [id]=#id
IF ##ROWCOUNT = 0
INSERT INTO MyTable ( ID, Name ) VALUES ( #id, #name )
END
CLOSE cur1
DEALLOCATE cur1
--COMMIT TRANSACTION
Is it possible you have an implicit transaction started in ODBC that needs an explicit COMMIT to end (after the call to the SP)? SSMS generally uses autocommit mode.
I solve my problem by adding SET NOCOUNT ON to start of my SP, so I think when SQL return multiple result set as a result of executing my SQL, ODBC close or cancel the command upon receiving first result set.