How to convert hours in varchar to complete a date variable in pl/sql? - plsql

I need to add a varchar value to my date variable in a stored procedure.
PROCEDURE TEST_CAL
(P_HOURS IN VARCHAR2
,P_DATE IN DATE
)
IS
V_DATE date;
BEGIN
V_DATE := P_DATE;
END;
Now V_DATE's value is 03.10.2022 and P_HOURS's value is '7' and I don't know how to add this value to V_DATE so it's value is 03.10.2022 7am.

Add a multiple of an hour interval:
V_DATE := P_DATE + TO_NUMBER(p_hours) * INTERVAL '1' HOUR;
or, use NUMTODSINTERVAL:
V_DATE := P_DATE + NUMTODSINTERVAL(TO_NUMBER(p_hours), 'HOUR');
or, use arithmetic:
V_DATE := P_DATE + TO_NUMBER(p_hours) / 24;
Even better, pass the hours as a number and not a string:
PROCEDURE TEST_CAL(
P_HOURS IN INTEGER
, P_DATE IN DATE
)
IS
V_DATE date;
BEGIN
V_DATE := P_DATE + p_hours * INTERVAL '1' HOUR;
END;
/
fiddle

Related

i am trying to covert time zone utc to asia/calcutta it show error ORA-01849 hour must between 1 and 12

create or replace procedure conv_date_1 is
v_date TIMESTAMP ;
begin
select to_char(from_tz(TO_TIMESTAMP(to_char(SYSDATE,'mm-dd-yyyy hh24:mi:ss'), 'mm-dd-yyyy hh24:mi:ss'),'UTC')
at time zone 'Asia/Calcutta','mm-dd-yyyy hh24:mi:ss') into v_date from dual;
dbms_output.put_line('Time is '|| v_date);
end;
this variable v_date is of type timestamp, as the query starts with to_char the variable should be of type varchar2 for example.

how to add HH:MI to systimestamp in PLSQL code with a HH:MI as variable

I want to replace '02:00' with a variable in the below code in PLSQL procedure.
SELECT SYSTIMESTAMP + interval '02:00' HOUR TO MINUTE
INTO est_close_date
FROM DUAL;
Define the variable as the number of hours, then you can do:
declare
l_number_of_hours integer;
...
begin
...
l_number_of_hours := 6;
SELECT SYSTIMESTAMP + interval '1' HOUR * l_number_of_hours
INTO est_close_date
FROM DUAL;
end;
If you need finer granularity, use minutes:
declare
l_number_of_minutes integer;
...
begin
...
l_number_of_minutes := 2 * 60 + 30;
SELECT SYSTIMESTAMP + interval '1' minute * l_number_of_minutes
INTO est_close_date
FROM DUAL;
end;

How to use for loop in sql developer or oracle

This is my code but while I'm running the project, it's showing error like
PLS-00306: wrong number or types of arguments in call to 'TEST_PROCEDURE'
I want to insert multiple records according given date.
CREATE OR REPLACE PROCEDURE TEST_PROCEDURE (
IP_START_DATE IN VARCHAR2,
IP_END_DATE IN VARCHAR2,
IP_MATERIAL_TYPE IN VARCHAR2,
IP_BRM_LIST IN VARCHAR2,
IP_ACTUAL_CONSUMPTION IN VARCHAR2,
IP_YARD_NO IN VARCHAR2,
IP_USER_ID IN VARCHAR2,
IP_USER_IP IN VARCHAR2,
IP_RID IN NUMBER,
IP_OPERATION IN VARCHAR2,
i OUT VARCHAR2,
OUT_RETURN_MSG OUT VARCHAR2,
OUT_RETURN_CODE OUT NUMBER)
IS
BEGIN
OUT_RETURN_MSG := '';
OUT_RETURN_CODE := 0;
BEGIN
IF IP_OPERATION = 'INSERT'
THEN
FOR i IN IP_START_DATE .. IP_END_DATE
LOOP
IF i <= IP_END_DATE
THEN
-- exit loop immediately
INSERT INTO MST_ACTUAL_CONSUMPTION (FROM_DATE,
TO_DATE,
MATERIAL_TYPE,
BRM_TYPE,
ACTUAL_CONSUMPTION,
YARD_NO,
USER_ID,
USER_IP_ADDRESS,
CREATED_DATE)
VALUES (IP_START_DATE,
IP_END_DATE,
IP_MATERIAL_TYPE,
IP_BRM_LIST,
IP_ACTUAL_CONSUMPTION,
IP_YARD_NO,
IP_USER_ID,
IP_USER_IP,
SYSDATE);
EXIT;
END IF;
END LOOP;
END IF;
IF IP_OPERATION = 'UPDATE'
THEN
UPDATE MST_ACTUAL_CONSUMPTION
SET FROM_DATE = IP_START_DATE,
TO_DATE = IP_END_DATE,
MATERIAL_TYPE = IP_MATERIAL_TYPE,
BRM_TYPE = IP_BRM_LIST,
ACTUAL_CONSUMPTION = IP_ACTUAL_CONSUMPTION,
YARD_NO = IP_YARD_NO,
LAST_UPD_TS = SYSDATE,
LAST_UPD_UID = IP_USER_ID
WHERE RID = IP_RID;
-- AND VESSEL_NAME = IP_VESSEL_NAME;
END IF;
OUT_RETURN_CODE := 1;
OUT_RETURN_MSG := 'SUCCESS';
EXCEPTION
WHEN OTHERS
THEN
OUT_RETURN_CODE := 0;
OUT_RETURN_MSG := SQLERRM;
END;
END TEST_PROCEDURE;
You need to select the days between start and end and use that for your loop counter instead of trying to use the variables directly as you currently are. Even though you're passing varchar2 with dates inside them, I still trunc the casted variable for safety to guarantee a whole number.
select trunc(to_date(ip_end_date)) - trunc(to_date(ip_start_date))
into loop_count
from dual;
Change your loop to count by this
if loop_count > 0 then
FOR i IN 1..loop_count loop
and I'm assuming you probably want to change the date for each iteration of the loop to match the day between start and end.
Firstly, you shouldn't be using varchar2 datatype for date datatypes. That is asking for trouble.
Now, since you want to insert records for multiple dates, you can't use for loop iterator for dates the way you do it for numbers as in for i in 1..10.
So, you could use a connect by as a method to generate dates. Use LEVEL pseudocolumn to refer to the current iteration (i in the for loop)
INSERT INTO mst_actual_consumption (
from_date,
TO_DATE, -- don't use this as a column_name as it's a function
material_type,
brm_type,
actual_consumption,
yard_no,
user_id,
user_ip_address,
created_date
)
SELECT
ip_start_date, -- you need to use to_date if you are passing date as strings
ip_end_date,
ip_material_type,
ip_brm_list,
ip_actual_consumption,
ip_yard_no,
ip_user_id,
ip_user_ip,
SYSDATE
FROM
dual
CONNECT BY
level <= ( ip_end_date - ip_start_date ); -- you need to use to_date if you are passing date as strings
I did not understand this part though
IF i <= IP_END_DATE
THEN
-- exit loop immediately
Maybe you were trying this? If so, put it before insert and update
IF ip_end_date <= ip_start_date
THEN
RETURN;
END IF;
EDIT you said:
error has fixed but no records are inserting even one time also
It could be because you are not passing correct dates.As I said in the code comments, you should convert them to dates using to_date function.
For eg: if you are passing the dates as strings in the format dd-mm-yyyy, In the insert, you should use
level <= ( to_date(ip_end_date,'dd-mm-yyyy') - to_date(ip_start_date,'dd-mm-yyyy') )
Same thing has to be done in the select part of insert, if the column in table MST_ACTUAL_CONSUMPTION is of date datatype.
select to_date(ip_start_date,'dd-mm-yyyy'), to_date(ip_end_date,'dd-mm-yyyy')
you can't loop through dates, you can probably do something like this.
create or replace procedure testproc(
startdate in date,
enddate in date
)
as
datediff NUMBER := enddate-startdate;
newdate date := startdate;
begin
FOR i IN 1..datediff LOOP
newdate := newdate+1;
insert into temp values(newdate);
END LOOP;
end;
and for your error it's because you are passing your parameters incorrectly like passing a string where argument requires integer value or you are passing incorrect number of parameters.
create or replace PROCEDURE PROC_ADD_ACTUALCONSUMPTION (
IP_START_DATE IN VARCHAR2,
IP_END_DATE IN VARCHAR2,
IP_MATERIAL_TYPE IN VARCHAR2,
IP_BRM_LIST IN VARCHAR2,
IP_ACTUAL_CONSUMPTION IN VARCHAR2,
IP_YARD_NO IN VARCHAR2,
IP_USER_ID IN VARCHAR2,
IP_USER_IP IN VARCHAR2,
IP_RID IN NUMBER ,
IP_OPERATION IN VARCHAR2,
--S_DATE OUT DATE,
--E_DATE OUT DATE,
--datediff OUT NUMBER,
OUT_RETURN_MSG OUT VARCHAR2,
OUT_RETURN_CODE OUT NUMBER)
IS
BEGIN
OUT_RETURN_MSG := '';
OUT_RETURN_CODE := 0;
-- S_DATE :=TO_DATE(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS');
-- E_DATE :=TO_DATE(IP_END_DATE,'DD-MM-YYYY HH24:MI:SS');
-- datediff :=E_DATE-E_DATE;
BEGIN
IF IP_OPERATION = 'INSERT' THEN
INSERT INTO MST_ACTUAL_CONSUMPTION
(
FROM_DATE,
TO_DATE,
MATERIAL_TYPE,
BRM_TYPE,
ACTUAL_CONSUMPTION,
YARD_NO,
USER_ID,
USER_IP_ADDRESS,
CREATED_DATE
)
select
TO_CHAR((to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS')+ (level-1)),'DD-MM-YYYY') ,
TO_CHAR(to_date(IP_END_DATE,'DD-MM-YYYY HH24:MI:SS'),'DD-MM-YYYY') ,
IP_MATERIAL_TYPE,
IP_BRM_LIST,
IP_ACTUAL_CONSUMPTION,
IP_YARD_NO,
IP_USER_ID,
IP_USER_IP,
SYSDATE
FROM
dual
CONNECT BY
level <= to_date(IP_END_DATE,'DD-MM-YYYY HH24:MI:SS')-to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS')+1;
-- to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS'):=to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS')+1;
END IF;
END PROC_ADD_ACTUALCONSUMPTION;

getting wrong number or types of arguments in call to procedure

I am trying to call a procedure using below code and getting
wrong number or types of arguments in call to procedure
The issue could be with the record type being passed as parameter , but I couldn't see any issue with that .
DECLARE
p_status VARCHAR2 (4) := 'S';
p_id NUMBER := 123456;
p_py_id NUMBER := 513;
p_type NUMBER := 1;
p_date_time DATE := TO_DATE ('10/01/2018 23:50:42', 'DD/MM/YYYY HH24:MI:SS');
p_os_pay NUMBER := 0;
p_ind VARCHAR2 (2) := 'Y';
p_confirm VARCHAR2 (2) := 'Y';
p_year NUMBER := 2018;
p_reason VARCHAR2 (5) := NULL;
p_currrpay NUMBER := 1517;
p_details pkg.g_r_type;
BEGIN
p_details.pro_code := 'AB';
p_details.inst_type := '1';
p_details.pay_date := TO_DATE ('19/10/2016 00:00:00', 'DD/MM/YYYY HH24:MI:SS');
p_details.pay_amt := 5000;
p_details.h_code := 'ABCD';
p_details.pay_ind := 'N';
p_details.c_code := 123456;
p_details.c_year := 8;
pkg.procedure_info ( p_status,
p_id,
p_py_id,
p_type,
p_date_time,
p_os_pay,
p_ind,
p_confirm,
p_year,
p_reason,
p_details,
p_currrpay
);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;
/
Below is the package description :
CREATE OR REPLACE package pkg
as
type g_r_type is record (
pro_code varchar2 (2)
,inst_type varchar2 (1)
,pay_date date
,pay_amt number (13, 2)
,h_code varchar2 (4)
,pay_ind varchar2 (1)
,c_code number(6)
,c_year number(2)
);
procedure procedure_info (
p_status in varchar2
,p_id in number
,p_py_id in number
,p_type in number
,p_date_time in date
,p_os_pay in number
,p_ind in varchar2
,p_confirm in varchar2
,p_year in number
,p_failure_reason in varchar2
,p_details in g_r_type
,p_currrpay in number
);
end pkg;
/
I have cross checked the datatypes, length and number of arguments , but couldn't find the issue.
Make sure your package scripts end with a / at the very end of the text file, as the first char of the line (and last non blank).
If your package was created successfully, you should get a message:
package created successfully
Then if your package's Body is:
package body created successfully
To make sure your package is correctly created on the database:
This query should help:
Select * from all_source where name='PKG';
And for the body:
Select *
from all_source
where name='PKG'
and type='PACKAGE BODY';

Function to generate random date from period [duplicate]

I have this anonymous block:
DECLARE
V_DATA DATE;
BEGIN
V_DATA := '01-GEN-2000';
HR.STATISTICHE.RATINGOPERATORI (V_DATA);
COMMIT;
END;
but I would to generate the date in a random way. How can I do?
You can generate random dates between two dates ,as displayed in the query below .Random Dates are generated between 1-jan-2000 and 31-dec-9999
SELECT TO_DATE(
TRUNC(
DBMS_RANDOM.VALUE(TO_CHAR(DATE '2000-01-01','J')
,TO_CHAR(DATE '9999-12-31','J')
)
),'J'
) FROM DUAL;
OR you can use
SELECT TO_DATE (
TRUNC (
DBMS_RANDOM.VALUE (2451545, 5373484)
)
, 'J'
)
FROM DUAL
In the above example ,the first value is 01-Jan-2000 and the second value id 31-dec-9999
To generate random date you can use
select to_date('2010-01-01', 'yyyy-mm-dd')+trunc(dbms_random.value(1,1000)) from dual
or for random datetime
select to_date('2010-01-01', 'yyyy-mm-dd')+dbms_random.value(1,1000) from dual
If you want to see it's logic, you can also use this code.
create or replace procedure genDate(result out nvarchar2) IS
year number;
month number;
day number;
Begin
year:=FLOOR(DBMS_RANDOM.value(2000,2100));
month:=FLOOR(DBMS_RANDOM.value(1,12));
IF month=2 and (year/4)=0 and (year/100)!=0 then
day:=FLOOR(DBMS_RANDOM.value(1,29));
ELSIF month=2 or (year/100)=0 then
day:=FLOOR(DBMS_RANDOM.value(1,28));
ELSIF MOD(month,2)=1 then
day:=FLOOR(DBMS_RANDOM.value(1,31));
ELSIF MOD(month,2)=0 and month!=2 then
day:=FLOOR(DBMS_RANDOM.value(1,30));
END IF;
result:=month||'-'||day||'-'||year;
End;
here is one more option to generate date going back from now where 365 - days quanitity to move back from today, 'DD.MM.YYYY'- mask
to_char(sysdate-dbms_random.value()*365, 'DD.MM.YYYY')
I needed to generate employee data for testing. Each employee needed a date of birth that put them between 16 and 65 years of age, and a date of hire sometime between their 16th birthday and SYSDATE. Here's how...
FUNCTION randomDateInRange(alpha IN DATE, omega IN DATE) RETURN DATE IS
BEGIN
RETURN alpha + DBMS_RANDOM.VALUE(0, omega - alpha);
END;
...and then, to use this function...
-- an employee can be any age from 16 to 65 years of age
DoB := randomDateInRange(
SYSDATE - INTERVAL '65' YEAR,
SYSDATE - INTERVAL '16' YEAR
);
-- an employee could have been hired any date since their sixteenth birthday
DoH := randomDateInRange(
DoB + INTERVAL '16' YEAR,
SYSDATE
);

Resources