Last dateof month using pl/sql - sql

I want to write a programm using PL/SQL
If the date of birth of one person is 12th May 1978, so that the person retirement date should be 12th may 2038, but instead of 12th may 2038 the date of retirement of that person will be the last date of the same month (it will automatically redirect the last day of the same month).

Check function last_day
e.g.
select last_day(to_date('12/05/2038', 'dd/mm/yyyy')) from dual

Oracle has a last_day function that does exactly that:
select sysdate, last_day(sysdate) from dual;
SYSDATE LAST_DAY(SYSDATE)
--------- -----------------
19-DEC-13 31-DEC-13
From PL/SQL:
declare
month_end date;
begin
month_end := last_day(sysdate);
end;
... but pass in your adjusted date of birth value.

Related

More on extracting year from date - Oracle

I have a question about selecting year from a date. This is in Oracle database 12c.
Given that SELECT trunc(SYSDATE) FROM DUAL; returns 02/06/2020
These work proper and return current year of 2020 -
SELECT EXTRACT(YEAR FROM trunc(SYSDATE)) FROM DUAL;
SELECT TO_CHAR(trunc(SYSDATE,'YYYY')) FROM DUAL;
These do not work and give error -
SELECT EXTRACT(YEAR FROM '02/06/2019') FROM DUAL;
Gives error: ORA-30076: invalid extract field for extract source
SELECT TO_CHAR('02/06/2019','YYYY') FROM DUAL;
Gives error: ORA-01722: invalid number
The same format is being passed with sysdate and hard coded date of 02/06/2019. Why is it that one works and the other does not?
I know I could just select 2019 from dual but that is not the point or use case here.
You can't extract year from a string (which '02/06/2019' is). First convert it to date:
SQL> SELECT EXTRACT(YEAR FROM to_date('02/06/2019', 'dd/mm/yyyy')) year FROM DUAL;
YEAR
----------
2019
SQL>
Or, if you know that last 4 digits are valid year, then
SQL> select substr('02/06/2019', -4) year from dual;
YEAR
----
2019
SQL>
It comes down to the data type being passed. sysdate by default is a DATE field. A hard date like '02/06/2020' by default is considered a string.
To get around that, just cast the string as a date. All good.
SELECT TO_CHAR(cast('6-feb-2019' as date),'YYYY') FROM DUAL;

When 31st April or 29th Feb for non-leap year the date inserted in Oracle table it is 30 April instead of 31st and 28th Feb instead of 29th

Is this behavior expected? And why?
When 31st April or 29th February for non-leap year the date inserted in Oracle table it is 30 April instead of 31st and 28th February instead of 29th February.
Hmmm, if we do this ...
select date '2018-02-29' from dual;
... or this ...
select date '2018-04-31' from dual;
... Oracle will definitely hurl ORA-01847: day of month must be between 1 and last day of month.
But Oracle handles things when we do this :
select add_months(date '2018-01-29', 1) from dual;
select add_months(date '2018-03-31', 1) from dual;
Instead of hurling an error Oracle returns the last day of the next month, 2018-02-28 and 2018-04-30 respectively. So it's being helpful and catching a silly error caused by the quirks of the Western calendar, which seems fair enough (although you may choose to disagree). However, it has one, er, interesting side-effect. This ...
select add_months(date '2018-02-28', 1) from dual;
... returns 2018-03-31 because last day of month, which may not always be expected or desired.
Here is a SQLFiddle to play with.
As #zirhc points out, INTERVAL behaves differently, and this ...
select date '2018-01-29' + interval '1' month from dual;
... will hurl the expected ORA-01839: date not valid for month specified.
Maybe you want to capture the error if the date is invalid.
Let's say you ran below script. Obviously, an error will be thrown because the date is invalid.
ALTER SESSION SET NLS_DATE_FORMAT='MM/DD/YYYY';
DECLARE
v_date DATE;
BEGIN
v_date := '04/31/2018'';
END;
/
Error report -
ORA-01839: date not valid for month specified
ORA-06512: at line 4
01839. 00000 - "date not valid for month specified"
If you want capture the error, you can do it by defining an exception.
DECLARE
v_date DATE;
ORA_1839 EXCEPTION;
PRAGMA EXCEPTION_INIT(ORA_1839, -1839);
BEGIN
v_date := '04/31/2018';
EXCEPTION
WHEN ORA_1839 THEN
DBMS_OUTPUT.PUT_LINE('ERROR 1839 HAD CAUGHT');
END;
/

Oracle SQL Create Date from Parts

I have two date fields in a database called "EFFECTIVE_DATE" and "POINT_DATE"
How do I create a new date field, where the date is made up from the year of "EFFECTIVE_DATE", the month of "POINT_DATE" and the day of "POINT_DATE" ?
I would normally use Datefromparts, but this is an Oracle Database not Microsoft
Kind Regards
Here's an approach using ADD_MONTHS and EXTRACT(YEAR FROM ....). You simply add or subtract the needed number of months (always a multiple of 12, since you are only changing the year). Unlike the TO_CHAR / TO_DATE solutions, this approach handles leap days (Feb. 29). On the other hand, be advised that changing the date from 28 Feb. 2003 to the year 2012 will change it to Feb. 29 (ADD_MONTHS changes the last day of a month to the last day of the resulting month).
with
inputs as (
select date '2013-03-22' as effective_date,
date '2017-08-14' as point_date
from dual
)
-- end of TEST data (do not include in the solution!)
select effective_date, point_date,
add_months(point_date, 12 * ( extract (year from effective_date) -
extract (year from point_date) )
) as mixed_date
from inputs;
EFFECTIVE_DATE POINT_DATE MIXED_DATE
-------------- ---------- ----------
03/22/2013 08/14/2017 08/14/2013
Hmmm . . . this produces a nice string in the YYYY-MM-DD format:
select to_char(effective_date, 'YYYY') || '-' || to_char(point_date, 'MM-DD')
And this parses it back to a date:
select to_date(to_char(effective_date, 'YYYY') || '-' || to_char(point_date, 'MM-DD'), 'YYYY-MM-DD')
Note: You might want to be careful about Feb 29th.
Assuming all coulmns are DATE data types, you can use this one
TO_DATE(TO_CHAR(EFFECTIVE_DATE, 'YYYY') || TO_CHAR(POINT_DATE, 'MMDD'), 'YYYYMMDD')
Be aware of leap years!

Checking if date falls in a specified month in Oracle

procedure Charge(p_inputdate N VARCHAR2,//Date which accepts only MMYYYY format
inout_Cur OUT result_cur) IS
I need to validate the effective_date which is in date format (mm/dd/yyyy hh:mm:ss)
For example: The user enters 112013 as input and the effective date to check is 11/12/2013 09:13:22
Is it possible to find whether the effective date falls within the specified month?
can you please comment on this..
I tried below way:
V_INPUTDATE := to_char(TO_DATE(IN_INPUTDATE, 'MMYYYY','mmyyyy'));
v_effectiveDate := substr(V_INPUTDATE,1,2)+'/'+'01'+'/'+substr(V_INPUTDATE,3,4);
01 is nothing but month always start with 01(dd)
Is this rightway ..??
If date happens to be a VARCHAR2 you need to first convert it to DATE:
effective_date DATE; -- Put this line in the declare section
effective_date := to_date('11/12/2013 09:13:22', 'MM/DD/YYYY HH24:MI:SS');
When you have the date, the rest is easy:
IF p_inputdate = to_char(effective_date, 'MMYYYY') THEN
-- Date is ok.
ELSE
-- Date is not ok.
END IF;

How to extract week number in sql

I have a transdate column of varchar2 type which has the following entrees
01/02/2012
01/03/2012
etc.
I converted it in to date format in another column using to_date function. This is the format i got.
01-JAN-2012
03-APR-2012
When I'm trying to extract the weekno, i'm getting all null values.
select to_char(to_date(TRANSDATE), 'w') as weekno from tablename.
null
null
How to get weekno from date in the above format?
After converting your varchar2 date to a true date datatype, then convert back to varchar2 with the desired mask:
to_char(to_date('01/02/2012','MM/DD/YYYY'),'WW')
If you want the week number in a number datatype, you can wrap the statement in to_number():
to_number(to_char(to_date('01/02/2012','MM/DD/YYYY'),'WW'))
However, you have several week number options to consider:
WW Week of year (1-53) where week 1 starts on the first day of the year and continues to the seventh day of the year.
W Week of month (1-5) where week 1 starts on the first day of the month and ends on the seventh.
IW Week of year (1-52 or 1-53) based on the ISO standard.
Try to replace 'w' for 'iw'.
For example:
SELECT to_char(to_date(TRANSDATE, 'dd-mm-yyyy'), 'iw') as weeknumber from YOUR_TABLE;
Select last_name, round (sysdate-hire_date)/7,0) as tuner
from employees
Where department_id = 90
order by last_name;
Use 'dd-mon-yyyy' if you are using the 2nd date format specified in your answer. Ex:
to_date(<column name>,'dd-mon-yyyy')