Error while working with dates in pl/sql? - sql

This is how it's supposed to work:
I have a table called Pro2 with a column called finall that is a date and another one called validade. If finall has already happened or is happening validade is set to 0.
BEGIN
FOR validade in (SELECT * FROM PRO2 WHERE TRUNC(finall)<= TRNCU(SYSDATE))
LOOP
SET validade = 0
END LOOP;
END;
I'm new in PL/SQL please help!

You have an error in your second TRUNC command.
You aren't supposed to set validade (which is a CURSOR) to any value.
Assignment operator is := and not SET in PL/SQL.
Try this:
BEGIN
FOR r_record IN (SELECT *
FROM PRO2
WHERE TRUNC(finall) <= TRUNC(SYSDATE))
LOOP
UPDATE PRO2 t1
SET t1.validade = 0
WHERE t1.id = r_record.id;
END LOOP;
END;
You shouldn't use PL/SQL for such thing!
Use SQL when it is possible!
UPDATE PRO2
SET validade = 0
WHERE TRUNC(finall) <= TRUNC(SYSDATE);

Every well-designed Oracle table has a primary key, often called id or ending with it. That is what Alex meant by t1.id. You should ask for the column(-combination) that makes the primary key for PRO2 and substitute that.
DML code like the shown UPDATE can be included in PLSQL and is really the best solution:
BEGIN
-- other things here ....
UPDATE pro2
SET validade = 0
WHERE TRUNC( finall ) <= TRUNC( SYSDATE );
-- and here ...
END;

Related

Compare Date with Trigger on Oracle SQL

I have a table with those columns:
DateDebVal DATE
DateFinVal DATE
isCurrent NUMBER
And I need to have a trigger that do something like this:
CREATE TRIGGER check_date
AFTER INSERT OR UPDATE ON tablename
FOR EACH ROW
BEGIN
IF sysdate < DateFinVal
set isCurrent = 1
ELSE
set isCurrent = 0
END;
Can I compare those dates? Is it a good idea to use a trigger instead of a view or a procedure?
Dates can absolutely be compared, but assignment is done using := in PL/SQL (not with set)
If you want to change the value of a newly inserted row, you have to use a BEFORE trigger:
CREATE TRIGGER check_date
BEFORE INSERT OR UPDATE ON tablename
FOR EACH ROW
BEGIN
IF sysdate < :new.datefinval
:new.iscurrent := 1;
ELSE
:new.iscurrent := 0;
END IF;
END;
/
Online example: https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=796347f1b5811448dddf2d0a532c2c2c
Sysdate and DateFinVal are of DATE type so you would compare those. It depends what for you need this trigger.

Wondering why my SQL statement is ignoring my SET symbol

This is my SQL trigger and it is suppose to change the reorder value to Y or N depending if ON_HAND is less than or greater than the MINIMUM. The problem is it's ignoring the set statement completely. Do I have to arrange these differently?
CREATE OR REPLACE TRIGGER TRG_REORDER
AFTER UPDATE OF ON_HAND, MINIMUM ON PART
BEGIN
IF ON_HAND <= MINIMUM THEN
SET REORDER = 'Y';
ELSE ON_HAND > MINIMUM
SET REORDER = 'N';
END IF;
END;
Trigger bodies use PL/SQL syntax, not SQL. So for assignment you need := not set.
Your code has some other syntax errors.
You need to refer to the :new values of the columns.
You don't need a condition in the ELSE clause.
In order to modify the values of columns in a trigger, it must be a BEFORE trigger and fire FOR EACH ROW.
So fixing all that, this should now work for you (caveat: untested code).
CREATE OR REPLACE TRIGGER TRG_REORDER
before UPDATE OF ON_HAND, MINIMUM ON PART
for each row
BEGIN
IF :new.ON_HAND <= :new.MINIMUM THEN
:new.REORDER = 'Y';
ELSE
:new.REORDER = 'N';
END IF;
END;
I don't know Oracle triggers but I suspect you want a BEFORE trigger and an assignment that looks something like this.
:new.REORDER := case when :new.ON_HAND <= :new.MINIMUM then 'Y' else 'N' end;
Check here to get started:
http://www.techonthenet.com/oracle/triggers/before_update.php

UPDATE table with PL/SQL trigger?

I have this trigger, and I am getting an arror message when I run it; "bad bind variable".
I can't seem to see where the problem lies. Any help would be appreciated.
create or replace TRIGGER trg_placed AFTER UPDATE
OF STATUS_ID ON STATUS
FOR EACH ROW
BEGIN
IF :new.STATUS_ID = 7
THEN
UPDATE STUDENT
SET PLACED_Y_N = 'Y'
WHERE RECORD_NUMBER = :NEW.record_number;
END IF;
END;
try like this:
create or replace TRIGGER trg_placed AFTER UPDATE
OF STATUS_ID ON STATUS
REFERENCING OLD AS o NEW AS n
FOR EACH ROW
BEGIN
IF n.STATUS_ID = 7
THEN
UPDATE STUDENT
SET PLACED_Y_N = 'Y'
WHERE RECORD_NUMBER = n.record_number;
END IF;
END;
If you use lowercase for Oracle objects, you'll have to surround object names with quotes (") and match the case exactly to get it to work.
like this
create or replace TRIGGER trg_placed AFTER UPDATE
OF STATUS_ID ON STATUS
FOR EACH ROW
BEGIN
IF :new.STATUS_ID = 7
THEN
UPDATE STUDENT
SET PLACED_Y_N = 'Y'
WHERE RECORD_NUMBER = :NEW."record_number"; --quotes (") required for column name.
END IF;
END;

Automatically update a column in a table with a trigger

I'm having a problem with a trigger code (table mutation and more!) and I can't find
what is the problem.
Basically, I have a table SEMESTER(id_semester, semester_name, begin_date, end_date).
On the insertion of a row, I want the semester_name to be updated with a value according
to what's in begin_date. For example, if the begin_date is '2000-01-01', I want the value of
semester_name to be W00 (for winter 2000).
My first try was to write an 'after insert' trigger, which didn't work because of a table mutation error. Here it is:
CREATE TRIGGER Test
BEFORE INSERT ON Semester
FOR EACH ROW
DECLARE
sem CHAR(1);
year CHAR(2);
BEGIN
-- begin_date is either 1, 5 or 9.
IF (EXTRACT(MONTH FROM :new.begin_date) = '1') THEN
saison := 'W';
ELSIF (EXTRACT(MONTH FROM :new.begin_date) = '5') THEN
saison := 'S';
ELSE
saison := 'F';
END IF;
year := TO_CHAR(:new.date_debut, 'MM');
UPDATE Semester
SET semester_name = CONCAT(sem, year)
WHERE id_semester = :new.id_semester;
END;
/
After, I tried to make a 'before insert' trigger, thinking it would work better but it does not.
Anyone could point me in the right direction?
Thanks!
Assuming id_semester is the primary key, instead of an UPDATE statement, you would just want to assign the :new.semester_name
:new.semester_name := concat( sem, year );
The mutanting table error occurs only with "each row" kind of triggers, try to change your after insert trigger for a "statement" type

Cursor locking the table

declare
CURSOR C1
IS select tgt.exp_date ,(src.eff_date - 1/(24*60*60))eff_date
from mira_rate tgt,mira_rate_dummy src
where src.tc_code = tgt.tc_code and src.carrier_code = tgt.carrier_code and tgt.exp_date is null for update of tgt.exp_date;
v_a date;
v_b date;
i number:=0;
begin
open c1;
loop
fetch c1 into v_a, v_b;
exit when c1%notfound;
update mira_rate
set exp_date =v_b where current of c1;
i:=i+1;
end loop;
dbms_output.put_line(i||' rows updated');
close c1;
commit;
end;
After i excecute the query it is locking the table says
ORA-00054: resource busy and acquire with NOWAIT specified
Also pls tell me how to remove the lock i tried killing the sesssion it is not happening.still it says the same
Affter removing the lock. Pls clear me this requirement
select tgt.exp_date ,(src.eff_date - 1/(24*60*60))eff_date
from mira_rate tgt,mira_rate_dummy src
where src.tc_code = tgt.tc_code and src.carrier_code = tgt.carrier_code and tgt.exp_date is null;
it ill return rows I need to goto the mira_rate table need to update exp_date=eff_date.
Please suggest me how to do i m using Oracle 9i so merge without not matched is working
At first sight, there is no commit in the code.
The code with commit wil be ok. Commit will release the locks(Oracle cursor examples/expl)
But better you would:
MERGE INTO mira_rate tgt
USING mira_rate_dummy src
ON (src.tc_code = tgt.tc_code and src.carrier_code = tgt.carrier_code)
WHEN MATCHED THEN UPDATE
SET exp_date= src.eff_date - 1/(24*60*60) --or just src.eff_date
WHERE tgt.exp_date is null;
This is what you want to do as far as I understand.
As a rule: What you can do in SQL, do in SQL, not PL/SQL.
Take out the 'FOR UPDATE'.
You need to be very clear in your mind why you need it and in my experience you generally don't.
Between us I think we are saying this should be your approach
begin
UPDATE mira_rate
SET exp_date= src.eff_date - 1/(24*60*60)
WHERE exp_date is null;
DBMS_OUTPUT.PUT_LINE
(TO_CHAR(SQL%ROWCOUNT) || ' Rows Updated);
end;
No need for locks and no need for cursors.
Hope that helps.
Edit - still not entirely sure what your requirement is but the following sql may be what you are looking for.
UPDATE MIRA_RATE TGT
SET EXP_DATE =
(
SELECT SRC.EFF_DATE - 1/86400
FROM MIRA_RATE_DUMMY SRC
WHERE
SRC.TC_CODE = TGT.TC_CODE AND
SRC.CARRIER_CODE = TGT.CARRIER_CODE
)
WHERE
TGT.EXP_DATE IS NULL;
#Satheesh, Updatable select will work only for primary key columns. See if the select fetches the primary key and also useins it in where clause. Else the update will throw error.
There is something to check for
cannot modify a column which maps to a non key-preserved table
You can have join but the update needs primary key to update in the base table.