Oracle converting an INSERT to MERGE ot not EXISTS - sql

I have the following code, which is working fine. If I run the procedure more than once with the same values I get a PRIMARY KEY violation, which I expect. Could the INSERT be converted into a MERGE or NOT EXISTS to avoid this issue?
The examples I saw online appear to be using literal values or an ON statement with the MERGE.
As I am a novice SQL developer any help or sample code, which reflects my requirement would be greatly appreciated.
Thanks in advance to all who answer.
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
/
CREATE OR REPLACE FUNCTION generate_dates_pipelined(
p_from IN DATE,
p_to IN DATE
)
RETURN nt_date PIPELINED DETERMINISTIC
IS
v_start DATE := TRUNC(LEAST(p_from, p_to));
v_end DATE := TRUNC(GREATEST(p_from, p_to));
BEGIN
LOOP
PIPE ROW (v_start);
EXIT WHEN v_start >= v_end;
v_start := v_start + INTERVAL '1' DAY;
END LOOP;
RETURN;
END generate_dates_pipelined;
/
create table schedule_assignment(
schedule_id number(4),
schedule_date DATE,
employee_id NUMBER(6) DEFAULT 0,
constraint sa_chk check (schedule_date=trunc(schedule_date, 'dd')),
constraint sa_pk primary key (schedule_id, schedule_date)
);
CREATE OR REPLACE PROCEDURE
create_schedule_assignment (
p_schedule_id IN NUMBER,
p_start_date IN DATE,
p_end_date IN DATE
)
IS
BEGIN
INSERT INTO schedule_assignment(
schedule_id,
schedule_date
)
SELECT
p_schedule_id,
COLUMN_VALUE
FROM TABLE(generate_dates_pipelined(p_start_date, p_end_date));
END;
EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');

Rewrite procedure to
SQL> CREATE OR REPLACE PROCEDURE
2 create_schedule_assignment (
3 p_schedule_id IN NUMBER,
4 p_start_date IN DATE,
5 p_end_date IN DATE
6 )
7 IS
8 BEGIN
9 merge into schedule_assignment s
10 using (select p_schedule_id as schedule_id,
11 column_value as schedule_date
12 from table(generate_dates_pipelined(p_start_date, p_end_date))
13 ) x
14 on ( x.schedule_id = s.schedule_id
15 and x.schedule_date = s.schedule_date
16 )
17 when not matched then insert (schedule_id, schedule_date)
18 values (x.schedule_id, x.schedule_date);
19 END;
20 /
Procedure created.
SQL>
Testing: initially, table is empty:
SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
2 from schedule_assignment group by schedule_id;
no rows selected
Run the procedure for the 1st time:
SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');
PL/SQL procedure successfully completed.
Table contents:
SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
2 from schedule_assignment group by schedule_id;
SCHEDULE_ID MINDAT MAXDATE COUNT(*)
----------- ---------- ---------- ----------
1 21/08/2021 30/08/2021 10
Run the procedure with same parameters again:
SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');
PL/SQL procedure successfully completed.
SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');
PL/SQL procedure successfully completed.
SQL> EXEC create_schedule_assignment (1, DATE '2021-08-21', DATE '2021-08-30');
PL/SQL procedure successfully completed.
Result: nothing changed, no rows in table (but no error either):
SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
2 from schedule_assignment group by schedule_id;
SCHEDULE_ID MINDAT MAXDATE COUNT(*)
----------- ---------- ---------- ----------
1 21/08/2021 30/08/2021 10
SQL>
Run the procedure with the same SCHEDULE_ID, but different dates:
SQL> EXEC create_schedule_assignment (1, DATE '2021-08-29', DATE '2021-09-02');
PL/SQL procedure successfully completed.
SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
2 from schedule_assignment group by schedule_id;
SCHEDULE_ID MINDAT MAXDATE COUNT(*)
----------- ---------- ---------- ----------
1 21/08/2021 02/09/2021 13
SQL>
Right; number of rows is now increased to 13 (was 10 previously, because 31.08., 01.09. and 02.09. were added).
New SCHEDULE_ID:
SQL> EXEC create_schedule_assignment (2, DATE '2021-09-05', DATE '2021-09-07');
PL/SQL procedure successfully completed.
SQL> select schedule_id, min(schedule_date) mindat, max(schedule_date) maxdate, count(*)
2 from schedule_assignment group by schedule_id;
SCHEDULE_ID MINDAT MAXDATE COUNT(*)
----------- ---------- ---------- ----------
1 21/08/2021 02/09/2021 13
2 05/09/2021 07/09/2021 3
SQL>
Looks OK to me.

Related

Oracle difficulty creating a procedure that has subquery

I am attempting to build a procedure that will INSERT rows into the table emp_attendance.
I call a procedure that generates a list of dates based on a range. I then join that table with each employee_id.
Being a novice SQL developer, I am having difficulty trying to understand why the procedure create_emp_attendance is not being created.
Below is my test CASE. Once I get the rows working for the SELECT I will add the INSERT code as I am trying to take the one little piece at a time.
Thanks in advance for your help and expertise.
ALTER SESSION SET NLS_DATE_FORMAT = 'MMDDYYYY HH24:MI:SS';
CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
CREATE OR REPLACE FUNCTION generate_dates_pipelined(
p_from IN DATE,
p_to IN DATE
)
RETURN nt_date PIPELINED DETERMINISTIC
IS
v_start DATE := TRUNC(LEAST(p_from, p_to));
v_end DATE := TRUNC(GREATEST(p_from, p_to));
BEGIN
LOOP
PIPE ROW (v_start);
EXIT WHEN v_start >= v_end;
v_start := v_start + INTERVAL '1' DAY;
END LOOP;
RETURN;
END generate_dates_pipelined;
CREATE SEQUENCE batch_seq
START WITH 1
MAXVALUE 999999999999999999999999999
MINVALUE 1
NOCYCLE
CACHE 20
NOORDER;
Create table employees(
employee_id NUMBER(6),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
card_num VARCHAR2(10),
work_days VARCHAR2(7)
);
INSERT INTO employees (
employee_id,
first_name,
last_name,
card_num,
work_days
)
WITH names AS (
SELECT 1, 'John', 'Doe', 'D564311','YYYYYNN' FROM dual UNION ALL
SELECT 2, 'Justin', 'Case', 'C224311','YYYYYNN' FROM dual UNION ALL
SELECT 3, 'Mike', 'Jones', 'J288811','YYYYYNN' FROM dual UNION ALL
SELECT 4, 'Jane', 'Smith', 'S564661','YYYYYNN' FROM dual
) SELECT * FROM names;
CREATE TABLE emp_attendance(
seq_num integer GENERATED BY DEFAULT AS IDENTITY (START WITH 1) NOT NULL,
employee_id NUMBER(6),
start_date DATE,
end_date DATE,
week_number NUMBER(2),
create_date DATE DEFAULT SYSDATE
);
CREATE OR REPLACE PROCEDURE create_emp_attendance (
p_start_date IN DATE,
p_end_date IN DATE
)
IS l_batch_seq number;
BEGIN
SELECT get_batch_seq INTO l_batch_seq FROM dual;
SELECT
employee_id,
start_date,
start_date+NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(3600,43200)), 'SECOND') AS end_date,
to_char(start_date,'WW') AS week_number
FROM (
-- Need subquery to generate end_date based on start_date.
SELECT
e.employee_id, d.COLUMN_VALUE+ NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND') AS start_date
FROM employees e
INNER JOIN TABLE( generate_dates_pipelined(p_start_date, p_end_date)
) d
) ed
END;
EXEC create_emp_attendanc(DATE '2021-08-07', DATE '2021-08-14');
You didn't refer to the sequence, so I removed that. Your SELECT needs to have a target via INTO clause or be used within the context of an INSERT (or other) statement. The JOIN was missing an ON clause. But you appeared to want a CROSS JOIN.
If you really want to INSERT in one statement, here's the form:
CREATE OR REPLACE PROCEDURE create_emp_attendance (
p_start_date IN DATE,
p_end_date IN DATE
)
IS
BEGIN
INSERT INTO emp_attendance (employee_id, start_date, end_date, week_number)
SELECT employee_id
, start_date
, start_date+NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(3600,43200)), 'SECOND') AS end_date
, to_char(start_date,'WW') AS week_number
FROM ( -- Need subquery to generate end_date based on start_date.
SELECT e.employee_id, d.COLUMN_VALUE + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND') AS start_date
FROM employees e
CROSS JOIN TABLE( generate_dates_pipelined(p_start_date, p_end_date) ) d
) ed
;
END;
/
EXEC create_emp_attendance(DATE '2021-08-07', DATE '2021-08-14');
/
-- Procedure CREATE_EMP_ATTENDANCE compiled
-- PL/SQL procedure successfully completed.
Read comments within code.
SQL> CREATE OR REPLACE PROCEDURE create_emp_attendance
2 (
3 p_start_date IN DATE,
4 p_end_date IN DATE
5 )
6 IS
7 l_batch_seq number;
8 BEGIN
9 -- there's no GET_BATCH_SEQ function (at least, you didn't post it)
10 -- SELECT get_batch_seq INTO l_batch_seq FROM dual;
11 l_batch_seq := batch_seq.nextval;
12
13 -- In order to avoid TOO_MANY_ROWS, switching to a cursor FOR loop
14 for cur_r in
15 (SELECT
16 employee_id,
17 start_date,
18 start_date+NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(3600,43200)), 'SECOND') AS end_date,
19 to_char(start_date,'WW') AS week_number
20 FROM (-- Need subquery to generate end_date based on start_date.
21 SELECT
22 e.employee_id,
23 d.COLUMN_VALUE + NUMTODSINTERVAL(FLOOR(DBMS_RANDOM.VALUE(0,86399)), 'SECOND') AS start_date
24 FROM employees e
25 -- not INNER, but CROSS join (or, if it were INNER, on which column(s)?)
26 CROSS JOIN TABLE(generate_dates_pipelined(p_start_date, p_end_date)) d
27 ) ed
28 ) loop
29 -- you'll probably have INSERT statement here, according to what you said
30 null;
31 end loop;
32 END;
33 /
Procedure created.
Testing:
SQL> EXEC create_emp_attendance(DATE '2021-08-07', DATE '2021-08-14');
PL/SQL procedure successfully completed.
SQL>

convert epoch time into normal datetime format in Oracle SQL

Well, I am going to convert the epoch into a normal datetime in oracle sqldeveloper, I wrote the below code, but it says "missing expression"
My code:
SELECT to_date(CreationDate, 'yyyymmdd','nls_calendar=persian')+ EpochDate/24/60/60
from table1
My table1:
ID
EpochDate
100
16811048
101
16810904
102
12924715
103
15667117
I don not know what is wrong!
If the CreationDate is a Date and EpochDate is a Varchar you can try this:
SELECT to_date(to_char(CreationDate, 'yyyymmdd','nls_calendar=persian'),'yyyymmdd') +
EpochDate/24/60/60 as newDate
from table1
or:
select to_date(to_char(CreationDate, 'yyyymmdd','nls_calendar=persian'),'yyyymmdd') +
numtodsinterval(EpochDate,'SECOND') as newDate
from dual
Let's show you how in an example
Demo data
SQL> create table c1 ( id number generated always as identity, date_test date) ;
Table created.
SQL> insert into c1 ( date_test ) values ( sysdate ) ;
1 row created.
SQL> insert into c1 ( date_test ) values ( sysdate-365 ) ;
1 row created.
SQL> insert into c1 ( date_test ) values ( sysdate-4000 ) ;
1 row created.
SQL> insert into c1 ( date_test ) values ( sysdate-7200 ) ;
1 row created.
SQL> commit ;
Commit complete.
Now, let's add a column called epoch, and a small function to make easier to update the column.
SQL> alter table c1 add epoch number ;
Table altered.
SQL> create or replace function date_to_unix_ts( PDate in date ) return number is
l_unix_ts number;
begin
l_unix_ts := ( PDate - date '1970-01-01' ) * 60 * 60 * 24;
return l_unix_ts;
end;
/
Function created
We update the column epoch with the real epoch date based on the timestamp field
SQL> update c1 set epoch=date_to_unix_ts (date_test) ;
4 rows updated.
SQL> select * from c1 ;
ID DATE_TEST EPOCH
---------- ---------------------------------------- -----------------
1 2021-09-15 12:25:25 1631708725
2 2020-09-15 12:25:25 1600172725
3 2010-10-03 12:25:25 1286108725
4 2001-12-29 12:25:26 1009628726
SQL> select to_char(to_date('1970-01-01','YYYY-MM-DD') + numtodsinterval(EPOCH,'SECOND'),'YYYY-MM-DD HH24:MI:SS') from c1 ;
TO_CHAR(TO_DATE('19
-------------------
2021-09-15 12:25:25
2020-09-15 12:25:25
2010-10-03 12:25:25
2001-12-29 12:25:26

Writing triggers of a table to automatically update another table

I got these tables (Oracle):
Doctors (Doctor_ID (PK),
Doctor_Name,
DoB,
Specialization)
Doctors_At_Work (Doctor_ID (PK),
The_Date (PK),
Hour_Start (PK),
Hour_Stop,
Room)
Consultations_Intervals (Doctor_ID (PK),
The_Date (PK),
Start_Hour_Consult (PK),
Stop_Hour_Consut,
Room)
OBS: A consultation last for only 30 minutes.
My task is to create the necessary triggers (insert/update/delete) of Doctors_At_Work in order to automatically update the Consultations_Intervals table.
What I did so far:
Create sequence seq_id_doctor START with 1 INCREMENT BY 1 ORDER NOCACHE;
CREATE OR REPLACE trigger t_1
BEFORE INSERT ON Doctors_At_Work FOR EACH ROW
BEGIN
:NEW.Doctor_ID:=seq_id_doctor.NextValue;
:NEW.The_Date:=CURRENT_TIMESTAMP;
:NEW.Hour_Start:=Select Extract (Hour from CURRENT_TIMESTAMP);
END;
/
CREATE OR REPLACE trigger t_2
AFTER INSERT OR UPDATE ON Consultations_Intervals FOR EACH ROW
BEGIN
INSERT INTO Consultations_Intervals VALUES
(:NEW.Doctor_ID, :NEW.The_Date, :NEW.Hour_Start, :NEW.Hour_Start +
interval '30' minute, :NEW.Room);
END;
/
What is wrong with it? How should I solve this task? (if there are other ideas)
All you need a simple trigger on your Doctors_At_work table. See example below:
Tables:
create table Doctors_At_Work (Doctor_ID number Primary key,
The_Date date ,
Hour_Start date ,
Hour_Stop date,
Room number);
create table Consultations_Intervals (Doctor_ID number,
The_Date date ,
Start_Hour_Consult number,
Stop_Hour_Consut number,
Room number);
Trigger:
create or replace trigger t_1
before insert or update or delete on doctors_at_work
for each row
begin
insert into consultations_intervals (doctor_id,
the_date,
start_hour_consult,
stop_hour_consut,
room)
values (:new.doctor_id,
current_timestamp,
extract (minute from current_timestamp),
extract (minute from current_timestamp),
:new.room);
end;
/
Output:
SQL> Prompt "Before trigger"
"Before trigger"
SQL> select * from Doctors_At_Work;
no rows selected
SQL> select * from Consultations_Intervals;
no rows selected
SQL> create or replace trigger t_1
before insert or update or delete on doctors_at_work
2 3 for each row
4 begin
insert into consultations_intervals (doctor_id,
5 6 the_date,
7 start_hour_consult,
8 stop
.
.
.
Trigger created.
SQL> Insert into DOCTORS_AT_WORK
(DOCTOR_ID, THE_DATE, HOUR_START, HOUR_STOP, ROOM)
Values
(2, TO_DATE('12/18/2016 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('12/13/2016 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), TO_DATE('12/14/2016 00:00:00', 'MM/DD/YYYY HH24:MI:SS'), 12);
COMMIT;
2 3 4
1 row created.
SQL>
Commit complete.
SQL> select * from Doctors_At_Work;
DOCTOR_ID THE_DATE HOUR_STAR HOUR_STOP ROOM
---------- --------- --------- --------- ----------
2 18-DEC-16 13-DEC-16 14-DEC-16 12
SQL> select * from Consultations_Intervals;
DOCTOR_ID THE_DATE START_HOUR_CONSULT STOP_HOUR_CONSUT ROOM
---------- --------- ------------------ ---------------- ----------
2 19-DEC-16 17 17 12

Delete Oracle rows based on size

I have this Oracle table which I want to clean from time to time when I reach 2000 rows of data:
CREATE TABLE AGENT_HISTORY(
EVENT_ID INTEGER NOT NULL,
AGENT_ID INTEGER NOT NULL,
EVENT_DATE DATE NOT NULL
)
/
How I can delete the oldest row from the table when the table reaches 2000 rows?
You can delete all but the newest 2000 rows with the following query:
DELETE FROM agent_history a
WHERE 2000 < ( SELECT COUNT(1) cnt FROM agent_history b WHERE b.event_date < a.event_date )
The query checks every row in the table (a) to see how many rows have an event_date LESS than that row. If there are more than 2000 rows less than it, then it will delete that row.
Let me know if this doesn't work.
Create a DBMS_JOB or DBMS_SCHEDULER, that kicks off after certain interval and call a procedure. In that procedure check the count and delete the rows based on event_date.
Sorry, I didn't see your comment until now. Here is the code you were looking for. Make sure you have the grants to create scheduler program and jobs. This code assumes that the event_id is a sequence of #s and keeps up with the event_date. Otherwise change the rank based on both time and id or of your choice. Also you can change time interval. Check DBMS_SCHEDULER package documentation for any errors and corrections.
create or replace procedure proc_house_keeping is
begin
delete
from (
select rank() over (order by event_id desc) rnk
from agent_history
)
where rnk > 2000;
commit;
end;
/
begin
dbms_scheduler.create_program(
program_name => 'PROG_HOUSE_KEEPING',
program_type => 'STORED_PROCEDURE',
program_action => 'PROC_HOUSE_KEEPING',
number_of_arguments => 0,
enabled => FALSE,
comments => 'Procedure to delete rows greater than 2000');
end;
/
begin
dbms_scheduler.create_job(
job_name => 'table_house_keeping',
program_name => 'PROG_HOUSE_KEEPING',
start_date => dbms_scheduler.stime,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=1',
end_date => dbms_scheduler.stime+1,
enabled => false,
auto_drop => false,
comments => 'table house keeping, runs every minute');
end;
/
An approach may be adding a trigger to your table, so that it checks and deletes the oldest rows at every INSERT statement; for example, assuming not more than 3 rows:
CREATE OR REPLACE TRIGGER DELETE_3
AFTER INSERT ON AGENT_HISTORY
DECLARE
vNum number;
minDate date;
BEGIN
delete AGENT_HISTORY
where (event_id, agent_id, event_date) in
( select event_id, agent_id, event_date
from (
select event_id, agent_id, event_date, row_number() over (order by event_date desc) num
from AGENT_HISTORY
)
where num > 3 /* MAX NUMBER OF ROWS = 3*/
);
END;
Say we insert 5 rows:
SQL> begin
2 insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 1, 1, sysdate);
3 dbms_lock.sleep(1);
4 insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 2, 2, sysdate);
5 dbms_lock.sleep(1);
6 insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 3, 3, sysdate);
7 dbms_lock.sleep(1);
8 insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 4, 4, sysdate);
9 dbms_lock.sleep(1);
10 insert into AGENT_HISTORY(EVENT_ID , AGENT_ID, EVENT_DATE) values ( 5, 5, sysdate);
11 commit;
12 end;
13 /
PL/SQL procedure successfully completed.
we only have the newest 3:
SQL> select * from AGENT_HISTORY;
EVENT_ID AGENT_ID EVENT_DATE
---------- ---------- ---------------------------------------------------------------------------
3 3 18-FEB-16 17:05:24,000000
4 4 18-FEB-16 17:05:25,000000
5 5 18-FEB-16 17:05:26,000000

plsql insert, update for existing id

I have to write a stored proc for the below requirement.
Desired output : TAX table
CATEGORY_ID TAX_PERCENTAGE FROM_DATE CREATE_DATE TAX_ID TO_DATE
-------------------------------------------------------------------------------------
1 10 4/1/2012 12/19/2013 8:54:20 PM 61 31-MAR-13
1 12.5 4/1/2013 12/19/2013 8:54:44 PM 62 31-dec-9998
When a new CATEGORY_ID say 1 with tax_percentage 10 for business year(from_date) 4/1/2012 is inserted, then a default value should be placed in to_date column say 31-dec-9998. When i try to input the same cat_id 1 with diff set of values say tax_percentage 12.5, this time from_date 4/1/2013 then to_date value should be (from_date-1) of cat_id 1,tax_percent 10 and my to_date value of 10,cat_id=1 should be updated with default date 31-dec-9998.something like this
CREATE OR REPLACE procedure SCOTT.Sp_SaveNewTaxPercentage
(
iv_category_id number,
iv_tax_percentage varchar2,
iv_from_date varchar2,
iv_to_date varchar2 default '12/31/9998' ,
iv_created_date date,
ov_err_code out nocopy varchar2,
ov_err_msg out nocopy varchar2
)
is
lv_category_id varchar2(25);
LV_TO_DATE varchar2(25);
lv_cat_id varchar2(12);
begin
ov_err_code:=0;
for J in ( SELECT CATEGORY_ID,FROM_DATE FROM TAX_P WHERE CATEGORY_ID =IV_CATEGORY_ID)
loop
SELECT to_date(iv_from_date,'dd/mm/yyyy') -1 INTO LV_TO_DATE FROM DUAL;
lv_cat_id := J.CATEGORY_ID;
end loop;
update tax_p set TO_DATE=LV_TO_DATE where CATEGORY_ID =lv_cat_id;
commit;
IF lv_cat_id IS NULL THEN
LV_TO_DATE := iv_to_Date;
END IF;
insert into tax_p( TAX_ID , CATEGORY_ID ,TAX_PERCENTAGE, FROM_DATE ,TO_DATE,CREATE_DATE)
values(tax_seq.nextval,iv_category_id,iv_tax_percentage,iv_from_date,LV_TO_DATE,sysdate);
select 'Successfully Saved' into ov_err_msg from dual;
commit;
Exception
when others then
rollback;
ov_err_code:=1;
ov_err_msg:='Error while saving'||SQLERRM;
end Sp_SaveNewTaxPercentage;
/
show errors;
I think you don't need to loop records to update the to_date field, just a single UPDATE statement will work for you.
BEGIN
UPDATE tax_p
SET to_date = to_date(iv_from_date,'dd/mm/yyyy') -1
WHERE category_id = iv_category_id;
INSERT INTO tax_p(tax_id, category_id, tax_percentage, from_date, to_date, create_date)
VALUES(tax_seq.nextval, iv_category_id, iv_tax_percentage, iv_from_date, iv_to_date, SYSDATE);
COMMIT;
EXCEPTION WHEN ...
...
END;