Character to number conversion error in trigger - oracle

How will the trigger insert between two timings? Getting character to number conversion error in the if condition while inserting. Below is my trigger.
create or replace trigger TRI_INSERT
after insert on stud_details
referencing old as old new as new
for each row
declare
strTime varchar2(20) := :new.time_stamp; -- (eg: '02/08/2013 11:09:42 PM')
begin
if (to_char(strTime, 'hh24:mi:ss') between '22:00:00' and '23:59:59') then
insert into stud_clas_details
(id,
v-id,
w-id,
al_id,
time,
Time_Stamp)
values
(seq_ve_id.nextval,
:new.vehicle_id,
:new.way_id,
'xxxx',
strTime,
sysdate);
end if;
end TRI_INSERT;

you cannot to_char() a varchar2 with a date format and expect it to work.
instead you should do
if (to_char(:new.time_stamp, 'hh24:mi:ss') between '22:00:00' and '23:59:59') then
also if you want to insert the time into the table in a specific format, use
to_char(:new.time_stamp, 'hh24:mi:ss')
as with
strTime varchar2(20) := :new.time_stamp;
you will just be inserting the date in whatever the default NLS_DATE_FORMAT is for that session (which may vary per session).

How about instead using:
if extract(hour from :new.time_stamp) in (22,23) then ...

Problem in the if condition.. Now its working fine.. Thanks for all.
create or replace trigger TRI_INSERT
after insert on stud_details
referencing old as old new as new
for each row
declare
strTime varchar2(20) := :new.time_stamp; -- (eg: '02/08/2013 11:09:42 PM')
strFromTime varchar2(20):= '22:00:00'
strToTime varchar2(20):= '23:59:59'
begin
if ((to_char(strTime, 'hh24:mi:ss') > strFromTime) and (to_char(strTime,
'hh24:mi:ss') < strToTime)) then
insert into stud_clas_details
(id,
v-id,
w-id,
al_id,
time,
Time_Stamp)
values
(seq_ve_id.nextval,
:new.vehicle_id,
:new.way_id,
'xxxx',
strTime,
sysdate);
end if;
end TRI_INSERT;

Related

Using a date variable in a query to fetch records based on a given date in oracle

I need to write a function in oracle plsql that with take a date as an input and return records from a table for that particular day. If no date is given then fetch the records for current day.
Note that the column (purchase_date) is a timestamp(6) type not null column and has an index on it so I would not like to use trunc() function on the column.
Example value present in purchase_date column is --> 01-DEC-21 06.14.06.388855001 AM
create or replace FUNCTION getRecordsForDate(
input_date DATE DEFAULT SYSDATE
) RETURN sys_refcursor IS
data_out SYS_REFCURSOR;
BEGIN
OPEN data_out FOR
SELECT
p.product_name,
p.product_type,
p.purchased_by
FROM
product_details p
WHERE
AND p.purchase_date BETWEEN TO_DATE(input_date, 'DD-MON-YY')
-- AND TO_DATE('03-MAR-22 23:59:59', 'DD-MON-YY HH24:MI:SS'); --harcoded value works but I need to use input_date
AND 'TO_DATE' ||'(''' || input_date || ' 23:59:59''' ||',' || '''YYYY-MM-DD HH24:MI:SS''' ||')';
return data_out;
END getRecordsForDate;
My concatenation is not working in the last line. It gives me ORA-01858: a non-numeric character was found where a numeric was expected. Not sure what's wrong here. Would someone be able to help.
Do not use TO_DATE on a DATE.
The last line of the cursor will not work as it is a (concatenated) string literal that cannot be converted to a TIMESTAMP or a DATE.
Even if it did work (which it will not), your purchase_date is a TIMESTAMP(6) data type so you are going to exclude all value from the time 23:59:59.0000001 until 23:59:59.999999.
You want to use:
create or replace FUNCTION getRecordsForDate(
input_date DATE DEFAULT SYSDATE
) RETURN sys_refcursor
IS
data_out SYS_REFCURSOR;
BEGIN
OPEN data_out FOR
SELECT product_name,
product_type,
purchased_by
FROM product_details
WHERE purchase_date >= TRUNC(input_date)
AND purchase_date < TRUNC(input_date) + INTERVAL '1' DAY;
return data_out;
END getRecordsForDate;
/

How to prevent trigger from updating the timestamp on a column in Oracle?

I have a table which has a column on which I have set a trigger to update the timestamp when there is an update on the row
CREATE TABLE mytable (
id NUMBER NOT NULL,
sid VARCHAR(10) NOT NULL,
stext VARCHAR(10),
tid VARCHAR(10),
ttext VARCHAR(10),
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT unique PRIMARY KEY (id) ENABLE
);
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
select systimestamp into :new.last_updated from dual;
END;
/
However, when certain SQLs are executed on the table, I do NOT want the 'last_updated' column to be updated. For instance, when the below SQL updates this table, I do NOT want the trigger to kick in. I need the column to retain the last_updated value so that my other queries do not get messed up. However, when other SQLs do updates on the data, I want the column to be updated.
Any ideas on how this could be done?
MERGE INTO mytable
USING dual
ON (id = ?)
WHEN MATCHED THEN
UPDATE SET
stext = case when sid = ? then ? else stext end,
ttext = case when tid = ? then ? else ttext end
You can easily keep a supplied value and only insert the current time if it is not supplied:
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
:new.last_updated := coalesce(:new.last_updated, systimestamp);
END;
If you do not want to fire trigger when you update STEXT or TTEXT columns please try this:
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
BEGIN
if (not updating('stext') and not updating('ttext')) then
:new.last_updated := systimestamp;
end if;
END;
Thanks
You can put that specific SQL Statement into a PROCEDURE in which the module info is updated for the concerned application(always call this statement from this procedure only) such as
CREATE OR REPLACE PROCEDURE Merge_Text AS
BEGIN
DBMS_APPLICATION_INFO.SET_MODULE($$plsql_unit,null);
MERGE INTO mytable
USING dual
ON (id = ?)
WHEN MATCHED THEN
UPDATE SET
stext = case when sid = ? then ? else stext end,
ttext = case when tid = ? then ? else ttext end;
END;
/
and then distinguish this caller module within the trigger such as
CREATE OR REPLACE trigger last_updated_trigger
BEFORE UPDATE ON mytable
FOR EACH ROW
v_module VARCHAR2(80);
v_action VARCHAR2(80);
BEGIN
DBMS_APPLICATION_INFO.READ_MODULE(v_module, v_action);
IF v_module != 'MERGE_TEXT' THEN
:new.last_updated := systimestamp;
END IF;
END;
/

How to use Trigger with joining 2 tables?

I have 2 tables one is Schedule_table :
SID NOT NULL NUMBER(38)
FNUMBER VARCHAR2(20)
DEPARTURE_TIME TIMESTAMP(6) WITH TIME ZONE
ARRIVAL_TIME TIMESTAMP(6) WITH TIME ZONE
PRICE NUMBER
The second table is Flight_table
FNUMBER NOT NULL VARCHAR2(20)
DEPARTURE_APCODE CHAR(3)
ARRIVAL_APCODE CHAR(3)
Fnumber is PK in Flight_table and FK in Schedule_table.
I want the trigger to fire when the PRICE gets changed in Schedule_table
Also, to print a message of (Fnumber, ARRIVAL_APCODE, DEPARTURE_TIME ,ARRIVAL_APCODE).
I wrote this Code, it did not work.
create or replace trigger schedule_trigger after update on schedule
for each row when (new. price <> old. price)
begin
dbms_output.put_line( 'the flight number ' || :new.fnumber|| DEPARTURE_APCODE ||DEPARTURE_TIME|| ' has changed to '||:new.price ||' From'||:old.price);
end;
You are referring to the columns of Flight table - DEPARTURE_APCODE and DEPARTURE_TIME directly inside trigger which is not possible.You need to use a select
to fetch those values.
CREATE OR REPLACE TRIGGER schedule_trigger AFTER
UPDATE ON schedule
FOR EACH ROW
WHEN ( new.price <> old.price )
DECLARE
v_departure_apcode flight.departure_apcode%TYPE;
v_arrival_apcode flight.arrival_apcode%TYPE;
BEGIN
SELECT
departure_apcode,
arrival_apcode
INTO
v_departure_apcode,v_arrival_apcode
FROM
flight
WHERE
fnumber =:new.fnumber;
dbms_output.put_line('The flight number '
||:new.fnumber
|| v_departure_apcode
|| v_arrival_apcode
|| ' has changed to '
||:new.price
|| ' From '
||:old.price);
END;
/
And note that using DBMS_OUTPUT.PUT_LINE() inside a trigger is of no use as SQL developer sometimes does not display your output. Better create a log table and insert the records into it in your trigger.
You may require a commit statement for the output to be displayed.
SET SERVEROUTPUT ON;
UPDATE Schedule SET PRICE = 2502.00 where fnumber = 'F2004' ;
commit;
Commit complete.
The flight number F2004AB CD has changed to 2502 From 2501

SQL trigger - nesting INSERT INTO in IF condition

I want to create trigger registring in new table employees whom salary is being raised above 5000 and didn't get salary higher than 5000 so far.
Trigger I wrote is returning error Error(2,41): PL/SQL: ORA-00984: column not allowed here.
Here's my trigger:
CREATE OR REPLACE TRIGGER emp_gotrich_trig BEFORE UPDATE OF salary ON employees
FOR EACH ROW BEGIN
IF :NEW.salary>5000 AND :OLD.salary<=5000 THEN
INSERT INTO emp_gotrich VALUES (employee_id, SYSDATE, :OLD.salary, :NEW.salary);
END IF;
END;
And here's emp_gotrich table:
CREATE TABLE emp_gotrich ( emp_id NUMBER(6), raise_date DATE, old_sal NUMBER(8,2), new_sal NUMBER(8,2) );
I guess that INSERT statemet isn't nested properly but i don't know what should i change.
I also tried to use 'WHEN' but i dont know where should i omitt colons, so it doeasn't work too.
CREATE OR REPLACE TRIGGER emp_getrich_log BEFORE UPDATE OF salary ON employees FOR EACH ROW
WHEN
NEW.salary>5000 AND OLD.salary<=5000;
BEGIN
INSERT INTO emp_gotrich VALUES(employee_id, SYSDATE, :OLD.salary, :NEW.salary);
END;
Please, help me find a way to run it.
You forgot to specify :OLD or :NEW on the employee_id value in your INSERT statement. I believe it should be:
INSERT INTO emp_gotrich
(EMP_ID, RAISE_DATE, OLD_SAL, NEW_SAL)
VALUES
(:OLD.employee_id, SYSDATE, :OLD.salary, :NEW.salary);
I suggest that a field list, such as the one I added, should always be included in an INSERT statement.

oracle trigger query

I have a trigger which is sending data from a table to another table in another database. all s working fine.
The prob is that there is a new concept of END DATE, in which, if END DATE is present for a person, the row should reach the other table on that particular date..
eg.: if someones end date is 31st august, it should go on that day only, but ofcourse, my trigger is firing on event change (when enddate is set to 31st august)..
Could you please suggest me what I can do to SET the row to go on ENDDATE.?
It doesn't sound like you don't want a trigger. It sounds like you want a job. For example, if you create a procedure that transfers all the rows whose end_date is today
CREATE OR REPLACE PROCEDURE move_rows_with_end_date(
p_end_date IN DATE DEFAULT trunc(SYSDATE)
)
AS
BEGIN
INSERT INTO table_name#remote_database( <<list of columns>> )
SELECT <<list of columns>>
FROM table_name
WHERE end_date = trunc(sysdate);
END;
Then you can create a job that runs the procedure every day at midnight
DECLARE
l_jobno PLS_INTEGER;
BEGIN
dbms_job.submit( l_jobno,
'BEGIN move_rows_with_end_date; END;',
trunc(sysdate+1),
'trunc(sysdate+1)' );
commit;
END;

Resources