I have a list of files in a directory /XX/XX_XX/XX that have the date as YYYYMMDD after the file name
Files20130726.xxx
Files20130727.xxx
Files20130728.xxx
Files20130729.xxx
Files20130730.xxx
Files20130731.xxx
I need to take the current system date and select the file that has the matching date
Example: (system date 7/31/2013 = File20130731.xxx)
I created a procedure that will select the file with the correct system date from the directory
PROCEDURE xxxxxx
uu_f_name VARCHAR2(20) := 'Files.xxx';
uu_infile utl_file.file_type;
BEGIN
CREATE DIRECTORY NEW_DIRECTORY as '/XX/XX_XX/XX';
uu_infile := utl_file.fopen('/XX/XX_XX/XX', to_date(substr(uu_f_name,6, sysdate), 'YYYYMMDD'), 'MM/DD/YYYY', 'r');
I don't really know how to declare the Files.xxx because it actually FilesYYYYMMDD.xxx (so not sure if I can just declare it as 'FilesYYYYMMDD')
I am stuck on how to select the current system date and match it with the correct file. This is what I have but I know that it is not correct but I am lost at how to do this.
to_date(substr(uu_f_name,6, sysdate), 'YYYYMMDD'), 'MM/DD/YYYY', 'r');
Make yourself familiar with:
Format Models.
How to convert strings to dates and other way round with to_char and to_date functions that use format models.
How to concatenate strings with concat function and || operator.
There's plenty of questions here about all of these subjects you can learn from.
Example that should get you started:
JANI#xe> select sysdate from dual;
SYSDATE
-------------------
2013-08-01 07:52:55
JANI#xe> select 'Files.' || to_char(sysdate, 'YYYYMMDD') || '.xxx' as filename from dual;
FILENAME
------------------
Files.20130801.xxx
JANI#xe> !cat so25.sql
declare
v_filename constant varchar2(32767) :=
'Files.' || to_char(sysdate, 'YYYYMMDD') || '.xxx';
begin
dbms_output.put_line('v_filename = ' || v_filename);
end;
/
JANI#xe> #so25.sql
v_filename = Files.20130801.xxx
PL/SQL procedure successfully completed.
JANI#xe>
After that we can come back to your UTL_FILE issues if you have any.
Related
Im fairly new pl/sql and im trying to create procedure that can take a date parameter from input, find and update the matching join date row(s) from student table I am working on but i cant seem to get a valid date and i'm not sure i properly configured my procedure from input your help would be appreciated, this is my code currently.
CREATE OR REPLACE PROCEDURE dateChanger (p_join_date IN DATE)
IS p_date DATE;
p_month VARCHAR2(3);
p_year VARCHAR2(4);
p_change VARCHAR2(11);
v_month VARCHAR2(3);
BEGIN
p_date := to_date(p_join_date, 'dd-mon-yyyy');
p_month := Extract(MONTH FROM p_date);
p_year := Extract(YEAR FROM p_date);
v_month := to_char(Extract(MONTH FROM student.join_date%TYPE), 'MON');
--expected result 01-(Month from p_date)-(Year from p_date) eg. 01-JUL-2021
p_change := '01-'+to_char(p_month, 'MON')+'-'+to_char(p_year, 'YYYY');-- date put back together
UPDATE Week03.t_student SET join_date = to_date(p_change, 'dd-mon-yyyy')
WHERE v_month = p_month; -- table updated where months match
RETURN(p_date || '-----' || p_change);
END;
/
ACCEPT jDate Date PROMPT 'Please Enter a valid date as dd-MON-YYYY eg. 13-JUL-2021';
DECLARE
dc VARCHAR2(11);
l_date student.join_date%type := &jDate; -- input from user saved to date type variable
BEGIN
dc := DATECHANGER(l_date);
SELECT DATECHANGER(l_date) INTO dc from dual;
END;
/
When i enter the date as 'dd-mon-yyy' or 'yyyy-mon-dd' and many other variations i get a pls 00905 & 00201 error any help would be appreciated. it seems the date input refuses all the variations i've tried.
From documentation:
DATE
Makes reply a valid DATE format. If the reply is not a valid DATE
format, ACCEPT gives an error message and prompts again. The datatype
is CHAR.
That means in this case result of accept of data is char format.
You should change you code a bit.
in announmous block
l_date student.join_date%type := &jDate; => l_date varchar2(100) := '&jDate'
and in procedure
(p_join_date IN DATE) => (p_join_date in varchar2)
Yea so for future references to anyone who may need to complete a similar task to mine here is how i solved my problem thanks a bit to #Arkadiusz Ćukasiewicz
CREATE OR REPLACE PROCEDURE dateChanger (p_join_date IN DATE)
BEGIN
UPDATE Week03.t_student SET join_date = trunc(join_date, 'MM');
END;
/
SELECT * FROM student;
BEGIN
dateChanger(to_date('2018-09-01', 'yyyy-mm-dd'));
END;
/
I have a column in oracle database table which is Varchar2. In this column I am storing date line 29-1-2021 or 28-12-2020. I want to retrieve data from below query between two dates then I am getting error of Invalid month. How can I resolve this issue ?
SELECT Line_Stop_Id, Function_name, Product_family, line_description, Reason_Category, Reason_detail,
Product_item, product_description, request_raised_date, request_raised_time, cm.EMP_NAME as raised_by, Lse.User_Closer_Description,
Cm1.Emp_Name as Closer_User, Lse.User_Closer_Date, Lse.Final_Closer_Description, Lse.Final_Closer_Date, Lse.Final_Closer_Time,
Cm2.Emp_Name as Final_Closer, Lse.Resource_Effected ,
ROUND(24*(sysdate - to_date(Request_Raised_Date
||' '
||request_raised_time, 'DD-Mon-RR HH24:MI:SS'))) AS TAT
FROM Xx_Lsp_Linestoppage_Entry lse
Left join Emp_Master cm ON Lse.Raised_By = Cm.Emp_No
Left join Emp_Master cm1 ON Lse.Closer_User = Cm1.Emp_No
Left join Emp_Master cm2 ON Lse.Final_Closed_By = Cm2.Emp_No
where TO_DATE(Lse.Request_Raised_Date, 'DD-Mon-RR') Between TO_DATE('01-Jan-21', 'DD-Mon-RR') and TO_DATE('29-Jan-21', 'DD-Mon-RR');
You should check the validity of your date values stored as strings before a conversion and do a cleanup of them (of fix them).
This can be done via, for example, cursor in PL/SQL block (or wrapped in function to export query results or filter by its value):
declare
l_date date;
begin
for r in (
select distinct
request_raised_time
from Xx_Lsp_Linestoppage_Entry
/*To reduce rows in cursor*/
where not regexp_like('^\d{2}-\d{2}-\d{4}')
) loop
begin
l_date := to_date(r.q, 'dd-mm-yyyy');
exception
when others then dbms_output.put_line('Invalid date: ' || r.q);
end;
end loop;
end;
/
db<>fiddle here
Note, that you need to quote dashes inside format to make it exact, because Oracle treats unquoted dash as any symbol from quite wide set of delimiters. So it will process 01/12/2020 as date '2020-12-01', not as invalid date.
select to_date('01/12/2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01-12-2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
select to_date('01$12$2021', 'dd-mm-yyyy') as dt from dual;
DT
--------------------
2021-12-01T00:00:00Z
Elapsed: 00:00:00.002
1 rows selected.
You are storing the date in the format 29-1-2020 (dd-mm-yyyy) so use this format in the to_Date
replace
DD-Mon-RR
with
dd-mm-yyyy
Probably being the Lse.Request_Raised_Date field of type varchar2 it contains more information than you need for your query.
I think the best way is to select a string that only identifies the part necessary for the identification of the date using the function:
substr(string , string start from , string lenght )
This is an example:
select to_date(substr('29-01-2021 23:01:55',1,10),'DD-MM-YYYY') from dual;
TO_DATE (SU
----------
29-01-2021
instead of my string '29 -01-2021 23:01:55 ' enter field Lse.Request_Raised_Date
You can use on conversion error:
to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS')
This returns NULL instead of an error.
Hopefully, this is a lesson on why you should not store date/time values as strings. You can actually look for the bad values using:
select Request_Raised_Date, request_raised_time
from Xx_Lsp_Linestoppage_Entry
where to_date(Request_Raised_Date || ' ' || request_raised_time
default null on conversion error, 'DD-Mon-YYYY HH24:MI:SS') is null and
Request_Raised_Date is not null
This may give you some ideas on how to fix the data.
I have a query.
i have a config table AB where a row is marked as "sysdate-360"
col1 ||col2
AB || sysdate-360
BC || sysdate -2
When i write a procedure to get date value from the config table AB i used.
v_date varchar(20);
cursor c1 as
select col2 from AB;
then
for ab_date in c1
loop
select ab_date.col2 into v_date from dual;
v_sql := 'delete from any_table where load_date <='||v_date;
execute immediate v_sql ;
commit;
end loop;
The procedure is compiled but when i execute I'm getting below error
ORA-01722: invalid number
ORA-06512: at "procedure", line 46
ORA-06512: at line 1
01722. 00000 - "invalid number"
*Cause:
*Action:
The sysdate -360 is considered as char but not as date since SYSDATE is itself a date right?
Please help.
If you handle only expressions SYSDATE +/- N I'd suggest to modify the config table as follows
ID SYSDATE_OFFSET
-- --------------
AB -360
BC -2
So you have a numeric offset to sysdate which can be queried this way:
select sysdate + (select SYSDATE_OFFSET from config where id = 'AB') s_360
from dual;
S_360
-----------------
25.02.16 21:46:50
So you may open a cursor with the query above.
If you can't change the table - define a view that removes the string sysdate and converts to number!
This looks quite fine to me. But why do you select into v_date? You get a string from the cursor which you can concatenate directly:
for ab_date in c1 loop
v_sql := 'delete from any_table where load_date <=' || ab_date.col2;
execute immediate v_sql ;
commit;
end loop;
At last this is simply the concatanation of two strings 'delete from any_table where load_date <=' and 'sysdate-360' which makes 'delete from any_table where load_date <= sysdate-360' - exactly the SQL string you want.
(That would look even better with a proper column name such as date_expression instead of col2.)
More elaborate explanation: The cursor gets you the string 'sysdate-360'. The query select ab_date.col2 into v_date from dual; is simply v_date := ab_date.col2;. But is v_date a string? If not, you get a conversion error, because 'sysdate-360' is just a string, nothing more. If you expect the DBMS to see that the string contains 'sysdate' which also happens to be the name of a system variable for the current time and then convert this magically, you expect to much.
Try the to_date function
TO_DATE(v_date)
I am working on a simple PL/SQL block that asks the user their Date Of Birth and calculates their age. I've used the months_between divided by 12 conversion but I am having trouble with the date conversion and date input from the user for the substitution variable. Please ignore the v_birthday_year as that is another part of the code I have to integrate in later.
I'm not sure the format that the user has to type in, ie 05-07-1980, or 06 Mar 1978 that would be acceptable, and how to calculate their age from what they put in.
My desired program is to write a PL/SQL program to accept the user's birthdate in this format DD-MON-YYYY, and calculates the Age in with 1 Decimal place. So I need it calculated out to one decimal place too.
Here is what I have, but I'm not sure what format to type in the DOB at the substitution variable input and the actual calculation with one decimal place. I'm just trying to see where I'm going wrong and how to correct it.
SET SERVEROUTPUT ON
DECLARE
--v_birthday_year NUMBER(4) := &v_birthday_year;
v_dob DATE := &v_dob
v_your_age NUMBER(3, 1);
BEGIN
v_your_age := TRUNC(MONTHS_BETWEEN(SYSDATE, v_dob))/12;
DBMS_OUTPUT.PUT_LINE ('Your age is ' || v_your_age);
END;
/
You may use any of these (pure sql)
SELECT months_between(sysdate, user_birth_date) /12 FROM dual;
or
SELECT floor(months_between(sysdate, user_birth_date) /12) FROM dual;
or
SELECT EXTRACT(YEAR FROM sysdate) - EXTRACT(YEAR FROM user_birth_date) FROM dual
or
SELECT (sysdate - user_birth_date) / 365.242199 FROM dual
Hope this will help
All SQL examples from others and me are probably better thing to use unless you are learning something about PL/SQL. Here's what I came up with:
DECLARE
v_dob DATE:= to_date('&v_dob', 'MM/DD/YYYY'); -- copy this line and you'll be fine
v_your_age NUMBER(3, 1);
BEGIN
v_your_age := TRUNC(MONTHS_BETWEEN(SYSDATE, v_dob))/12;
DBMS_OUTPUT.PUT_LINE ('Your age is ' || v_your_age);
END;
/
I passed 01/01/2010. Got this in output:
Your age is 3.1
Another SQL example:
SELECT empno, ename, hiredate
, TRUNC(MONTHS_BETWEEN(sysdate, hiredate)/12) years_of_service
FROM scott.emp
/
Create or replace function getAge(birthday date) return number is
v_your_age NUMBER(3, 1);``
BEGIN
v_your_age := floor(MONTHS_BETWEEN(SYSDATE, birthday))/12;
return v_your_age;
END;
/
then you call the function
BEGIN
DBMS_OUTPUT.PUT_LINE ('Your age is ' || getAge(to_date('10/10/2015','DD/MM/YYYY')));
end;
/
select dob,sysdate,trunc(months_between(sysdate,dob)/12) as year,
trunc(mod(months_between(sysdate,dob),12)) as month,
trunc(sysdate - add_months(dob,((trunc(months_between(sysdate,dob)/12)*12) + trunc(mod(months_between(sysdate,dob),12))))) as day
from emp;
I am trying to create a trigger in Oracle that compares two dates and then deletes records if the difference of the two dates falls below a certain value. I have a full date value with the format 'DD-MON-YYYY HH24MI' and then for the second date value, I want to concatenate a 'DD-MON-YYYY' value with a 'HH24MI' value.
The problem I am getting is that when I try to concat the date and time value together using to_char, and then using to_date on that returned value, it gives me a ORA-01481 invalid number format error. The relevant lines from the trigger itself are below. If anyone can help me out with this, it would be greatly appreciated!
CREATE OR REPLACE TRIGGER dateTrig
...
DECLARE
day date;
ftime date;
CURSOR c_table1 IS SELECT ...;
BEGIN
FOR entry IN c_table1 LOOP
day := to_date(entry.fdate);
ftime := to_date(to_char(day, 'DD-MON-YYYY') || ' ' || to_char(entry.dtime, 'HH24MI'), 'DD-MON-YYYY HH24MI'); -- this is the line that is causing the error
dbms_output.put_line(day || ', ' || ftime);
END LOOP;
END;
/
Since DTIME is not a date type, you cannot use TO_CHAR with a date format. If it's zero padded to a length of 4 characters, you can simplify it like this:
ftime := to_date(to_char(day, 'DD-MON-YYYY') || ' ' || entry.dtime, 'DD-MON-YYYY HH24MI');
I think your best to avoid using to_char's if you can and try to stick with functions that return values in their native date formats, this way you may also not need to run a to_date command on your string, you may have some success with the following or a close relation to it:
ftime := Trunc(Sysdate) || ' ' || Extract(Hour From entry.dtime) || ':' Extract(Minute From entry.dtime)
Best of luck