Oracle APEX SQL Date Time Import Procedure - sql

I have a field (v_date) that contains date and time value e.g.(30-07-2021 13:30)
I want to import to my table two new dates and time values according to this field.
The first will be seven days later (08-06-2021 13:30), and the second one will be 7 days and one hour later (08-06-2021 14:30).
This is my code:
create or replace PROCEDURE "PR_ADD_MASSIVE_SESSIONS"
(v_date date)
IS
v_counter_day number :=7;
v_session_temp_date date;
v_session_temp_end date;
BEGIN
v_session_temp_date := to_date(v_date, 'MM-DD-YYYY HH24:MI') + v_counter_day;
v_session_temp_end := to_date(v_date, 'MM-DD-YYYY HH24:MI') + (v_counter_day + (1/1440*60));
INSERT INTO SESSIONS (CLIENTS_ID, SESSION_AREA, SESSION_DATE, SESSION_STOP, PAYMENT_TYPE_ID, PRICE, STATUS, COMPLETED, PAYMENT_STATUS, SESSION_NO)
VALUES (5, 1, v_session_temp_date, v_session_temp_end, 2, 40, 1, 1, 1, 1);
END;
And I get this error: Ajax call returned server error ORA-01843: not a valid month.
I try with to_char but the compiler only wants to_date in order to have a successful procedure.

The variables v_session_temp_date and v_session_temp_date are defined as DATE. The function TO_DATE converts a string to a date. It should not be used on variables of type DATE. Remove the TO_DATE and you're good to go. Example code below (using an anonymous block, not a procedure)
CREATE TABLE sessions
(
clients_id NUMBER,
session_area NUMBER,
session_date DATE,
session_stop DATE,
payment_type_id NUMBER,
price NUMBER,
status NUMBER,
completed NUMBER,
payment_status NUMBER,
session_no NUMBER
);
Table SESSIONS created.
--original code
DECLARE
v_date date := SYSDATE;
v_counter_day number := 7;
v_session_temp_date date;
v_session_temp_end date;
BEGIN
v_session_temp_date := to_date(v_date, 'MM-DD-YYYY HH24:MI') + v_counter_day;
v_session_temp_end := to_date(v_date, 'MM-DD-YYYY HH24:MI') + (v_counter_day + (1/1440*60));
INSERT INTO SESSIONS (CLIENTS_ID, SESSION_AREA, SESSION_DATE, SESSION_STOP, PAYMENT_TYPE_ID, PRICE, STATUS, COMPLETED, PAYMENT_STATUS, SESSION_NO)
VALUES (5, 1, v_session_temp_date, v_session_temp_end, 2, 40, 1, 1, 1, 1);
END;
/
ORA-01843: not a valid month
ORA-06512: at line 7
01843. 00000 - "not a valid month"
*Cause:
*Action:
--fixed code
DECLARE
v_date date := SYSDATE;
v_counter_day number := 7;
v_session_temp_date date;
v_session_temp_end date;
BEGIN
v_session_temp_date := v_date + v_counter_day;
v_session_temp_end := v_date + (v_counter_day + (1/1440*60));
INSERT INTO SESSIONS (CLIENTS_ID, SESSION_AREA, SESSION_DATE, SESSION_STOP, PAYMENT_TYPE_ID, PRICE, STATUS, COMPLETED, PAYMENT_STATUS, SESSION_NO)
VALUES (5, 1, v_session_temp_date, v_session_temp_end, 2, 40, 1, 1, 1, 1);
END;
/
PL/SQL procedure successfully completed.

Related

Oracle SQL: Return a distinct list of days when inputting a min and max of a date field

Is the following the correct way to get a distinct list of days for a date range (min and max of a date field) I intend to create a sql view out of this:
with range as (
select min(date) start_date,
max(date) end_date
from table
)
select start_date + level - 1 AS "DATE",
extract(month from start_date + level - 1) AS "MONTH",
extract(year from start_date + level - 1) AS "YEAR"
from range
connect by level <= (
trunc(end_date) - trunc(start_date) + 1
);
Do you really need to create a DATE table when you can generate one on the fly if needed
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY';
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;
/
SELECT
c.COLUMN_VALUE
FROM
TABLE(generate_dates_pipelined(DATE '2022-07-01',
DATE '2022-07-31')) c

Insert records for 40years in table only date

I need to insert only date into a table MONTH_YEAR from 01-01-2010 to 01-01-2040:
For example, I need to insert record on my table month wise
DATE:
01-01-2010
01-02-2010
01-03-2010
01-04-2010
01-05-2010
01-06-2010
01-07-2010
01-08-2010
01-09-2010
01-10-2010
01-11-2010
01-12-2010
01-01-2011
01-02-2011
01-03-2011
01-04-2011
01-05-2011
.....................................
01-06-2040
01-07-2040
01-08-2040
01-09-2040
01-10-2040
01-11-2040
01-12-2040
Like this I want to insert only date into my table for month wise from 01-01-2010 to 01-01-2040
You can use a hierarchical query:
INSERT INTO month_year (column_name)
SELECT ADD_MONTHS(DATE '2010-01-01', LEVEL - 1)
FROM DUAL
CONNECT BY LEVEL <= 31*12;
Or a recursive query:
INSERT INTO month_year (column_name)
WITH range (dt) AS (
SELECT DATE '2010-01-01' FROM DUAL
UNION ALL
SELECT ADD_MONTHS(dt, 1)
FROM range
WHERE dt < DATE '2040-12-01'
)
SELECT dt FROM range;
db<>fiddle here
Row generator it is:
SQL> insert into month_year (datum)
2 select date '2010-01-01' + level - 1
3 from dual
4 connect by level <= date '2040-01-01' - date '2010-01-01' + 1;
10958 rows created.
SQL> select min(datum) min_date,
2 max(datum) max_date
3 from month_year;
MIN_DATE MAX_DATE
---------- ----------
01.01.2010 01.01.2040
SQL>
If you only need 1st of every month, then
SQL> insert into month_year (datum)
2 select add_months(date '2010-01-01', level - 1)
3 from dual
4 connect by level <= months_between(date '2040-01-01', date '2010-01-01') + 1;
361 rows created.
SQL>
Do you really need 40 years of dates, it seems unlikely or can you make due with a virtual calendar, where you specify a start and end_date and all the dates are generated for you. This example does every day in the range but feel free to modify it to produce what you need. I use it in several places.
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;
/

Add days/hours/minutes and months to time stamp

Is there a way to add days hours months and minutes into a timestamp that i want to insert the value of into a variable
I have separate variables for minutes,hours,days and months that I want to add to the timestamp
the timestamp format goes like this '04-FEB-21 10.25.12.013000 AM'
I tried using SELECT TO_TIMESTAMP(datecreated,'dd-mon-yyyy hh.mi.ss AM') + daysvar into duedate FROM dual; but it returns the error AM/A.M. or PM/P.M. required
daysvar contains the amount of days to be added to the timestamp
Thank you!
I have separate variables for minutes,hours,days and months that I want to add to the timestamp
Use NUMTODSINTERVAL:
DECLARE
datecreated VARCHAR2(30) := '04-FEB-21 10.25.12.013000 AM';
days INT := 1;
hours INT := 2;
minutes INT := 42;
seconds INT := 3;
duedate VARCHAR2(30);
BEGIN
duedate := TO_CHAR(
TO_TIMESTAMP(
datecreated,
'DD-MON-RR HH12.MI.SS.FF6 AM',
'NLS_DATE_LANGUAGE=American'
)
+ NUMTODSINTERVAL(days, 'DAY')
+ NUMTODSINTERVAL(hours, 'HOUR')
+ NUMTODSINTERVAL(minutes, 'MINUTE')
+ NUMTODSINTERVAL(seconds, 'SECOND'),
'DD-MON-RR HH12.MI.SS.FF6 AM',
'NLS_DATE_LANGUAGE=American'
);
DBMS_OUTPUT.PUT_LINE(duedate);
END;
/
db<>fiddle here
If you want to add months then use ADD_MONTHS; however, it returns a DATE (and not a TIMESTAMP) so you would lose the fractional seconds. You can add those back though:
DECLARE
datecreated VARCHAR2(30) := '04-FEB-21 10.25.12.013000 AM';
months INT := 4;
days INT := 1;
hours INT := 2;
minutes INT := 42;
seconds INT := 3;
created_date TIMESTAMP;
duedate VARCHAR2(30);
BEGIN
created_date := TO_TIMESTAMP(
datecreated,
'DD-MON-RR HH12.MI.SS.FF6 AM',
'NLS_DATE_LANGUAGE=American'
);
duedate := TO_CHAR(
CAST(ADD_MONTHS(created_date, months) AS TIMESTAMP)
+ NUMTODSINTERVAL(days, 'DAY')
+ NUMTODSINTERVAL(hours, 'HOUR')
+ NUMTODSINTERVAL(minutes, 'MINUTE')
+ NUMTODSINTERVAL(seconds, 'SECOND')
+ (created_date - CAST(created_date AS DATE)), -- Fractional seconds
'DD-MON-RR HH12.MI.SS.FF6 AM',
'NLS_DATE_LANGUAGE=American'
);
DBMS_OUTPUT.PUT_LINE(duedate);
END;
/
db<>fiddle here

Error: PL/SQL: Compilation unit analysis terminated?

Keep Getting the same error on both codes!!
DROP TABLE Date_Dimension CASCADE CONSTRAINTS ;
CREATE TABLE Date_Dimension
(
date_key NUMBER NOT NULL ,
full_date DATE ,
day_of_week NUMBER ,
day_num_in_month NUMBER ,
day_num_overall NUMBER ,
day_name VARCHAR2 (9) ,
day_abbrev VARCHAR2 (3) ,
week_num_in_year NUMBER ,
week_num_overall NUMBER ,
week_begin_date DATE ,
MONTH NUMBER ,
month_number_overall NUMBER ,
month_name VARCHAR2 (9) ,
month_abbrev VARCHAR2 (3) ,
quarter NUMBER ,
YEAR VARCHAR2 (20) ,
century NUMBER
) ;
ALTER TABLE Date_Dimension ADD CONSTRAINT Date_Dimension_PK PRIMARY KEY ( date_key ) ;
Create or replace PROCEDURE sp_DATE_DIMENSION(v_STARTDATE IN INT, v_END_YEAR IN INT) IS
v_STARTDATE DATE;
v_ENDDATE DATE;
v_STARTDATE Date := to_date('2005/01/01' || v_START_YEAR, 'YYYY/MM/DD');
v_ENDDATE Date := to_date('2020/12/31' || v_END_YEAR,'YYYY/MM/DD');
BEGIN
INSERT INTO
Date_Dimension
(date_key,full_date, day_of_week, day_num_in_month, day_num_overall, day_name, day_abbrev, week_num_in_year, week_num_overall, month, month_name, month_abbrev, quarter, year, century)
VALUES
(
'1',TO_DATE(v_STARTDATE, 'yyyy/mm/dd'), TO_NUMBER(v_STARTDATE, 'D'), TO_NUMBER(v_STARTDATE, 'DD'), TO_NUMBER(v_STARTDATE, 'DDD'), TO_CHAR(v_STARTDATE, 'DAY'), TO_CHAR(v_STARDATE, 'DY'), TO_NUMBER(v_STARTDATE, 'IW'), TO_NUMBER(v_STARTDATE, 'WW'), TO_NUMBER(v_STARTDATE, 'MM'), TO_CHAR (v_STARTDATE, 'MONTH'), TO_CHAR (v_STARTDATE, 'MON'), TO_NUMBER (v_STARTDATE, 'Q'), TO_CHAR (v_STARTDATE, 'YEAR'), TO_NUMBER (v_STARTDATE, 'CC')
)
;
IF v_STARTDATE > v_ENDDATE THEN
DBMS_OUTPUT.PUT_LINE ('ERROR IN CODE REGARDING DATES CHOSEN');
ELSE
WHILE v_STARTDATE <= V_ENDDATE LOOP
DBMS_OUTPUT.PUT_LINE ('Date : '||to_char(v_StartDate,'YYYY / MM / DD'));
v_STARTDATE := v_STARTDATE + 1;
END LOOP;
END IF;
END;
Your code gets
PLS-00410: duplicate fields in RECORD,TABLE or argument list are not permitted
You have duplicated the name startdate from the procedure's format argument list as a local variable; and then repeated both of them again. I think you meant the formal argument to just be the year, since it's a number. Your conversion to a date is also then wrong:
to_date('2005/01/01' || v_START_YEAR, 'YYYY/MM/DD')
... doesn't make sense, as you already have the year 2005 hard-coded.
I think for that part you want something more like:
create or replace PROCEDURE sp_DATE_DIMENSION(p_START_YEAR IN NUMBER, p_END_YEAR IN NUMBER) IS
l_START_DATE Date := to_date(p_START_YEAR ||'-01-01', 'YYYY-MM-DD');
l_END_DATE Date := to_date(p_END_YEAR ||'-01-01', 'YYYY-MM-DD');
BEGIN
with other variables references tweaked to match. In your insert you're passing the first value as the string '1' instead of the number 1. You then call to_date() against variables which are already dated; and you call to_number() with a format mask for a date element - for those you need to convert to a string, and then to a number. So that insert woudl become more like:
INSERT INTO Date_Dimension (date_key, full_date, day_of_week, day_num_in_month,
day_num_overall, day_name, day_abbrev, week_num_in_year, week_num_overall,
month, month_name, month_abbrev, quarter, year, century)
VALUES (1,
l_START_DATE,
TO_NUMBER(TO_CHAR(l_START_DATE, 'D')),
TO_NUMBER(TO_CHAR(l_START_DATE, 'DD')),
TO_NUMBER(TO_CHAR(l_START_DATE, 'DDD')),
TO_CHAR(l_START_DATE, 'DAY'),
TO_CHAR(l_START_DATE, 'DY'),
TO_NUMBER(TO_CHAR(l_START_DATE, 'IW')),
TO_NUMBER(TO_CHAR(l_START_DATE, 'WW')),
TO_NUMBER(TO_CHAR(l_START_DATE, 'MM')),
TO_CHAR(l_START_DATE, 'MONTH'),
TO_CHAR(l_START_DATE, 'MON'),
TO_NUMBER(TO_CHAR(l_START_DATE, 'Q')),
TO_CHAR (l_START_DATE, 'YEAR'),
TO_NUMBER(TO_CHAR(l_START_DATE, 'CC'))
);
It isn't good practice to use dbms_output for error messages, as (a) a calling program has no other indication that something is wrong, and (b) even in a simple client call a user may well not even have capture or display of those enabled. It's better to throw an exception:
IF l_START_DATE > l_END_DATE THEN
RAISE_APPLICATION_ERROR (-20001, 'ERROR IN CODE REGARDING DATES CHOSEN');
END IF;
WHILE l_START_DATE <= l_END_DATE LOOP
DBMS_OUTPUT.PUT_LINE ('Date : ' || to_char(l_START_DATE, 'YYYY / MM / DD'));
l_START_DATE := l_START_DATE + 1;
END LOOP;
END;
/
The exception will cause the procedure to terminate early, so you don't need the else part as nothing beyond that is reached anyway if the dates are wrong.
Even so, you probably really want to do the insert inside the loop so you create all the relevant rows; and it would make sense to do the check and exception throw right at the start (maybe comparing the years rather than the dates, but doesn't really matter. And probably other things I've forgotten - hopefully this will put you more towards the right track. You don't really need a procedure for this, or even PL/SQL, as it could be done in plain SQL and a single insert, but hopefully this is an exercise.

sysdate-1 not working in Oracle Jobs

I have a stored procedure in Oracle. I want to call it in JOBS of Oracle.
DECLARE
P_DATE DATE;
BEGIN
P_DATE := TO_DATE ('19/10/2016', 'DD/MM/YYYY');
MITRA.PENJUALAN_ANTAR_CABANG.REPORTKONSOLRK ( P_DATE );
COMMIT;
END;
the result is right when I execute P_DATE as '19/10/2016'. But when I change it like this below the result is not display.
DECLARE
P_DATE DATE;
BEGIN
P_DATE := TO_DATE (TRUNC (SYSDATE - 1), 'DD/MM/YYYY');
MITRA.PENJUALAN_ANTAR_CABANG.REPORTKONSOLRK (P_DATE);
COMMIT;
END;
What is my query mistake, while if I run select trunc(SYSDATE-1) from dual the date was right.
SYSDATE - 1 is already a date. Passing it to to_date will produce a syntax error. Just drop the to_date call and you should be fine:
P_DATE := TRUNC(SYSDATE - 1);