I am trying to create job which executes every monday on 04:00 with the script
declare
job number;
begin
sys.dbms_job.submit( job,
'CALC_LAST_WEEK_STAT();',
to_date('03-07-2017 04:00:00', 'dd-mm-yyyy hh24:mi:ss'),
trunc('NEXT_DAY(TRUNC(SYSDATE), "MONDAY") + 4/24'),'dd-mm-yyyy hh24:mi:ss');
commit;
end;
/
but i have error PLS-00306: wrong number or types of arguments in call to 'SUBMIT'
If you have a look at the documentation for DBMS_JOB.SUBMIT() you will see that the datatype for interval is VARCHAR2. You are passing a date whereas SUBMIT() expects the formula for working out the time of the next run.
So that would be
q'[(NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 4/24)]'
Related
I want to understand a dbms_job.submit statement
dbms_job.submit(jobno, 'xxxsome_pl_sql_statement',next_date,interval);
next_date evaluates to Last_Day(Sysdate) ----30-apr-22
interval evaluates to Last_Day(Add_Months(Sysdate,1)) ------31-may-22
sysdate for today is 13-apr-22
1.How to interpret 31-may-22 as the interval? Should I interpret the interval as the time between Last_Day(Sysdate) and Last_Day(Add_Months(Sysdate,1)),which is approximately one month?
2.The next date to run the job has already been set, why do we need to set the interval again?
NEXT_DATE is the next time the job should execute. INTERVAL is a SQL formula in varchar2 format to calculate subsequent executions, not a date itself, and should be enclosed in single quotes like the PL/SQL statement.
dbms_job.submit(jobno, 'some_pl_sql_statement',Last_Day(Sysdate),'Last_Day(Add_Months(Sysdate,1))');
LAST_DAY and ADD_MONTHS are SQL functions.
DBMS_JOB.SUBMIT(
job OUT BINARY_INTEGER,
what IN VARCHAR2,
next_date IN DATE DEFAULT SYSDATE,
interval IN VARCHAR2 DEFAULT 'NULL',
no_parse IN BOOLEAN DEFAULT FALSE,
instance IN BINARY_INTEGER DEFAULT ANY_INSTANCE,
force IN BOOLEAN DEFAULT FALSE);
dbms_job.submit(
what=>'some_plsql_statement;',
next_date=>Last_Day(Sysdate), -- last day of this month
interval=>'Last_Day(Add_Months(Sysdate,1))'); -- Last day of the next month after each execution
I need to calculate the YTD weekly average for the GROSS_AMOUNT
In the below script, the first part of the code gets the number of weeks. The second part of the code gets the YTD sum for that same time period
How do I write the SQL so I can retrieve the actual value of YtdTotal/TotalWeeks?
SELECT YtdTotal/TotalWeeks FROM DUAL; does not work
-- STORES NUMBER OF WEEKS SINCE BEGINING OF YEAR INTO THE VARIABLE, TotalWeeks
DECLARE
TotalWeeks NUMBER;
BEGIN
SELECT to_number(to_char(sysdate, 'WW')) - to_number(to_char(trunc(sysdate, 'year'),'WW'))
INTO TotalWeeks
FROM DUAL
-- (retrieves number of weeks since beginning of year)
END
-- STORES THE SUM OF GROSS)AMOUNT FOR THE WEEKS CALCULATED ABOVE - INTO THE
DECLARE
VARIABLE, YtdTotal
BEGIN
SELECT SUM(GROSS_AMOUNT)
INTO YtdTotal
FROM PARENTS
WHERE process_date BETWEEN
(next_day(TRUNC(sysdate, 'year'),'SUN'))
AND
(next_day(TRUNC(sysdate),'SAT')-7);
END;
Don't use two separate anonymous PL/SQL blocks - combine them into one!
If you want to return the result, then - instead of an anonymous PL/SQL block - create a function.
CREATE OR REPLACE FUNCTION f_test
return NUMBER
IS
totalweeks NUMBER;
ytdtotal NUMBER;
result NUMBER;
BEGIN
-- STORES NUMBER OF WEEKS SINCE BEGINING OF YEAR INTO THE VARIABLE, TotalWeeks
SELECT TO_NUMBER (TO_CHAR (SYSDATE, 'WW'))
- TO_NUMBER (TO_CHAR (TRUNC (SYSDATE, 'year'), 'WW'))
INTO totalweeks
FROM DUAL;
-- (retrieves number of weeks since beginning of year)
-- STORES THE SUM OF GROSS)AMOUNT FOR THE WEEKS CALCULATED ABOVE - INTO THE
SELECT SUM (gross_amount)
INTO ytdtotal
FROM parents
WHERE process_date BETWEEN (NEXT_DAY (TRUNC (SYSDATE, 'year'), 'SUN'))
AND (NEXT_DAY (TRUNC (SYSDATE), 'SAT') - 7);
-- the final result
result := ytdtogal / totalweeks;
RETURN result;
END;
/
Use it as
select f_test from dual;
Question:
fl_schedule(flno, departs, dtime, arrives, atime, price).
Create a trigger to allow insertion or updation only if Flight number CX7520 is scheduled on Tuesday, Friday and Sunday.
CREATE OR REPLACE TRIGGER flightsch_day
BEFORE INSERT OR UPDATE ON fl_schedule
FOR EACH ROW
WHEN (NEW.flno LIKE 'CX7520')
DECLARE
day NUMBER;
BEGIN
day:=EXTRACT(weekday FROM :NEW.departs);
IF day NOT IN(0,2,5) THEN
RAISE_APPLICATION_ERROR(-20000,'Flight number CX7520 can be scheduled only on Tuesday, Friday and Sunday.');
END IF;
END;
/
ERRORS:
SQL> SHOW ERRORS;
Errors for TRIGGER FLIGHTSCH_DAY:
LINE/COL ERROR
-------- -----------------------------------------------------------------
4/10 PLS-00122: FROM as separator is allowed only with specific
built-in functions
In order to be able to use WHEN (NEW.flno = 'CX7520') after FOR EACH ROW, UPDATE OF flno is needed for individual column flno
CREATE OR REPLACE TRIGGER flightsch_day
BEFORE INSERT OR UPDATE OF flno ON fl_schedule
FOR EACH ROW
WHEN (NEW.flno = 'CX7520')
DECLARE
BEGIN
IF TO_CHAR(:NEW.departs,'Dy','NLS_DATE_LANGUAGE=English') NOT IN ('Tue','Fri','Sun') THEN
RAISE_APPLICATION_ERROR(-20000,'Flight number CX7520 can be scheduled only on Tuesday, Friday and Sunday.');
END IF;
END;
/
or without that WHEN.. clause, take :NEW.flno = 'CX7520' into IF Statement :
CREATE OR REPLACE TRIGGER flightsch_day
BEFORE INSERT OR UPDATE ON fl_schedule
FOR EACH ROW
DECLARE
BEGIN
IF NOT ( TO_CHAR(:NEW.departs,'Dy','NLS_DATE_LANGUAGE=English') IN ('Tue','Fri','Sun')
AND :NEW.flno = 'CX7520' ) THEN
RAISE_APPLICATION_ERROR(-20000,'Flight number CX7520 can be scheduled only on Tuesday, Friday and Sunday.');
END IF;
END;
/
use day abbreviations containing NLS_DATE_LANGUAGE option.
Otherwise you can meet the unexpected situations.
displayed error stems from use of weekday within EXTRACT() function where use of day, month, year allowed for a date type variable, also hour, minute, second ..etc. if it's a datetime type variable is allowed, but not weekday
I have the following stored procedure which calculates the time taken for a merge statement
create or replace procedure ModAuditData(
O_UpdatedCount out int
,O_EndTime out timestamp
,O_Duration out int)
as
P_StartTime timestamp(3) WITH LOCAL TIME ZONE;
-- EndTime timestamp;
begin
P_StartTime:=to_timestamp(to_char(current_timestamp,'DD/MM/YYYY HH:MI:SS'),'DD/MM/YYYY HH:MI:SS');
-- merge Statment that does UPSERT
O_UpdatedCount :=SQL%ROWCOUNT;
commit;
O_EndTime:=to_timestamp(to_char(current_timestamp,'DD/MM/YYYY HH:MI:SS'),'DD/MM/YYYY HH:MI:SS');
begin
select extract( second from (O_EndTime-P_StartTime) )
into O_Duration
from dual;
Exception When others then
O_Duration:=0;
end;
end ModAuditData;
The Issue is
O_EndTime:=to_timestamp(to_char(current_timestamp,'DD/MM/YYYY HH:MI:SS'),'DD/MM/YYYY HH:MI:SS')
gives exact opposite of
P_StartTime:=to_timestamp(to_char(current_timestamp,'DD/MM/YYYY HH:MI:SS'),'DD/MM/YYYY HH:MI:SS');
in terms of AM/PM
What is the correct way to calculate the start and end time
CURRENT_TIMESTAMP is already a TIMESTAMP WITH TIME ZONE, there is no reason to convert it first to VARCHAR2 and then back again into a TIMESTAMP.
Also timestamp(3) (which provides precision up to millisecond) does not make much sense when you return duration as INTEGER, i.e. full seconds.
Try it like this:
P_StartTime timestamp(3) WITH TIME ZONE;
begin
P_StartTime := current_timestamp;
-- merge Statment that does UPSERT
O_UpdatedCount :=SQL%ROWCOUNT;
commit;
O_Duration := EXTRACT(SECOND FROM (current_timestamp - P_StartTime));
end;
In case of SQL*Plus consider to use TIMING command.
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;