How to get data ordered by month - sql

I could not get the data in an ordered format like APR, MAY, JUNE, JULY. I want to display data ordered by month.
This is what I'm currently doing:
SELECT (TO_CHAR (TRUNC (exec_end), 'DD-MON-YY'))
FROM tbl_dumps
WHERE exec_end >= TO_DATE (SYSDATE - 90)
GROUP BY TO_CHAR (TRUNC (exec_end), 'DD-MON-YY'),
TO_CHAR (TRUNC (exec_end), 'MON')
ORDER BY (TO_CHAR (TRUNC (exec_end), 'MON')) DESC
Below is the current OUTPUT:
01-MAY-18,
02-MAY-18,
03-MAY-18,
31-MAY-18,
O1-JUN-18,
02-JUN-18,
03-JUN-18,
04-JUN-18,
01-JUL-18,
02-JUL-18,
03-JUL-18,
26-APR-18,
27-APR-18,
28-APR-18.
This is how I want my OUTPUT:
26-APR-18,
27-APR-18,
28-APR-18,
01-MAY-18,
02-MAY-18,
03-MAY-18,
31-MAY-18,
O1-JUN-18,
02-JUN-18,
03-JUN-18,
04-JUN-18,
01-JUL-18,
02-JUL-18,
03-JUL-18.

From what I understood, you might need
select to_char(exec_end, 'dd-mon-yy')
from tbl_dumps
where exec_end >= trunc(sysdate) - 90
order by to_char(exec_end, 'mm')
Also, as sysdate - 90 looks like "3 months ago", consider using add_months(sysdate, -3) instead.

Related

how to check a date is in current financial year

I am trying to check a condition if given date is in current financial year i.e april to march. but not getting any idea how to do
code
select nvl(Count(1), 0)+1 from ASET where IPE='O' and irt in (SELECT EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, -3))
|| '-'
|| EXTRACT (YEAR FROM ADD_MONTHS (SYSDATE, 9))
FROM DUAL)
irt is date 01-09-2020.
I think the simplest approach is to offset the date column and sysdate by 3 months, and compare the year part:
where to_char(add_months(irt, -3), 'yyyy') = to_char(add_months(sysdate, -3), 'yyyy')

How to put Case in Where Statement for Oracle SQL

For the query below, I'm trying to pull a specific date range depending on the current day of the month. If it's the 20th or less (e.g. "2/7/2020") then I want the date range for January. Otherwise, I want the date range for February. Is it possible to be done with a case statement? Or there is a better way?
SELECT
account,
start_date,
amount
FROM
table1
WHERE
CASE
WHEN (
SELECT
CAST(EXTRACT(DAY FROM sysdate) AS NUMBER)
FROM
dual
) <= 20 THEN
start_date
BETWEEN '2020-01-01' AND '2020-01-31'
ELSE start_date BETWEEN '2020-02-01' AND '2020-02-29'
END
You can do this by avoiding the case statement and using truncate the date - 20 to the month, e.g.:
SELECT account,
start_date,
amount
FROM table1
WHERE start_date >= TRUNC(SYSDATE - 20, 'mm')
AND start_date < add_months(TRUNC(dt - 20, 'mm'), 1);
If you really had to use a CASE expression (you can't use a CASE statement in SQL), you would need to do something like:
SELECT account,
start_date,
amount
FROM table1
WHERE start_date >= CASE WHEN to_char(SYSDATE, 'dd') <= '20' THEN add_months(TRUNC(SYSDATE, 'mm'), -1) ELSE TRUNC(SYSDATE, 'mm') END
AND start_date < CASE WHEN to_char(SYSDATE, 'dd') <= '20' THEN TRUNC(SYSDATE, 'mm') ELSE add_months(TRUNC(SYSDATE, 'mm'), 1) END;
N.B. if you're using a function, you don't need to wrap it in a select .. from dual, you can use it directly in the SQL statement.
I've also assumed that you want a dynamic range, e.g. if the day of the month is 20 or less, the range is for the previous month, otherwise the current month.
ETA: You would use the above two queries if there is an index on the start_date column, otherwise you could simply do:
SELECT account,
start_date,
amount
FROM table1
WHERE TRUNC(start_date, 'mm') = TRUNC(SYSDATE - 20, 'mm');
Case statements return single values. As such you should pull out the start date and you'll need two case statements.
select account, start_date, amount
from table1 where
start_date between
(case
when (select cast(extract(day from sysdate) as number) from dual) <= 20 then '2020-01-01'
else '2020-02-01'
end) and
(case
when (select cast(extract(day from sysdate) as number) from dual) <= 20 then '2020-01-31'
else '2020-02-29'
end)
One method subtracts 20 days and then gets the month boundary:
where start_date >= trunc(sysdate - interval '20' day, 'MON') and
start_date < trunc(sysdate - interval '20' day, 'MON') + interval '1' month
This approach is index (and partition) friendly -- an appropriate index on start_date can be used. It is also safe if start_date has time components.
Note: You can use sysdate without having to use a subquery.
You can use or operator with last_day function as following:
Select * from your_table
Where (
start_date <= trunc(sysdate,'mm') + 20
and start_date between trunc(sysdate,'mm') - interval '1' month and trunc(sysdate,'mm') - 1
)
Or
(
start_date > trunc(sysdate,'mm') + 20
and start_date between trunc(sysdate, 'mm') and last_day(sysdate)
)
This approach will use index on start_date, if any.
Cheers!!
select account, amount, start_date
from table1
where ( ( (select cast (extract (day from sysdate) as number) from dual) <= 20
and start_date between date '2020-01-01' and date '2020-01-31')
or ( (select cast (extract (day from sysdate) as number) from dual) > 20
and start_date between date '2020-02-01' and date '2020-02-29')
);
Using CASE expressions as BETWEEN operands:
SELECT account
, start_date
, amount
FROM table1
WHERE start_date BETWEEN CASE
WHEN extract(day from sysdate) <= 20
THEN trunc(sysdate -interval '1' month, 'month')
ELSE trunc(sysdate, 'month')
END
AND CASE
WHEN extract(day from sysdate) <= 20
THEN last_day(sysdate -interval '1' month)
ELSE last_day(sysdate)
END

ORA-01839: date not valid for month specified, How to avoid leap year issues

I have a table that stores a valid "custom date" for each person. That date may legitimately be Feb 29 of a leap year. The thing is in my SQL for my report I need to pull the "last" mm/dd for from this custom date field for that employee as of the most recent year. This date is never in the future so I can compare the year in the date and if its the current year pull it as is. However if it's any previous year (can go back as far as 1900) I need to instead pull that MM/DD and as of last year. So you can see how this will be a problem since there is no Feb-29-2018.
I'm looking for the best solution on how to handle this. I need it in my select portion and my conditional block where this date I'm trying to derive has to be >= the applydtm date. Here is a sample query to replicate the error. Simply switching the Feb-29 date to Feb-28 will show it working since it doesn't encounter that invalid leap year date. I would be okay with all Feb 29 dates 'converting' to Mar 1st if need be as long as the code is efficient as possible. DB = Oracle 11g
WITH sampledata (actualcustomdtm, textfield, applydtm) AS (
SELECT
TO_DATE('02/29/2012 00:00:00','mm/dd/yyyy hh24:mi:ss'),
'Leap Year',
sysdate
FROM dual
UNION
SELECT
TO_DATE('01/15/2019 00:00:00','mm/dd/yyyy hh24:mi:ss'),
'Non-Leap Year',
sysdate
FROM dual
)
SELECT
actualcustomdtm,
CASE WHEN TO_CHAR(actualcustomdtm, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY')
THEN TO_CHAR(actualcustomdtm, 'MM/DD/YYYY')
ELSE TO_CHAR(actualcustomdtm, 'MM/DD')||'/'||TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -12), 'YYYY')
END AS "LASTACTCSTMDATE",
textfield,
applydtm
FROM sampledata
WHERE applydtm >=
TO_DATE(CASE WHEN TO_CHAR(actualcustomdtm, 'YYYY') = TO_CHAR(SYSDATE, 'YYYY')
THEN TO_CHAR(actualcustomdtm, 'MM/DD/YYYY')
ELSE TO_CHAR(actualcustomdtm, 'MM/DD')||'/'||TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE), -12), 'YYYY')
END, 'MM/DD/YYYY')
I believe this logic does what you want -- getting the most recent anniversary up to or including today's date:
select dte, add_months(dte, 12),
(case when to_char(dte, 'MMDD') > to_char(sysdate, 'MMDD')
then add_months(dte, 12 * (extract(year from sysdate) - extract(year from dte) - 1))
else add_months(dte, 12 * (extract(year from sysdate) - extract(year from dte)))
end)
from (select date '2016-02-29' as dte from dual union all
select date '2018-01-03' from dual
) x;

Current Financial Year to sysdate

I can't seem to find a straightforward sql without delving into PL SQL for always bringing current financial year in which case 01-04-2015 to sysdate. I want this to always update automatically so when it comes next financial year in 01/04/2016 it will bring whatever is held from that date to whenever the report is being run.
If anyone can please shed some light for me. thanks
sql is:
SELECT
PROPERTY.PRO_MANAGINGCOMPANY_DESCR,
PROPERTY.PRO_SCHEME_DESCR,
PROPERTY.PRO_SCHEME,
SUM(REPAIR_CURRENT.REP_ESTIMATED_COST) as "Estimated Cost",
nvl(SUM(REPAIR_CURRENT.REP_INVOICED_COST),SUM(REPAIR_CURRENT.REP_ESTIMATED_COST)) as "Estimated Cost Invoiced",
SUM(REPAIR_CURRENT.REP_INVOICED_COST) as "Invoice Cost",
to_char(REPAIR_CURRENT.REP_RAISED_DATE,'Mon') as "Month",
to_number(to_char(to_date(REPAIR_CURRENT.REP_RAISED_DATE,'dd-mon-yy'),'mm')) as "Month No."
FROM
PROPERTY,
REPAIR_CURRENT,
SERVICE_REQUEST
WHERE
( SERVICE_REQUEST.SRQ_PRO_REFNO=PROPERTY.PRO_REFNO )
AND ( REPAIR_CURRENT.REP_SRQ_NO=SERVICE_REQUEST.SRQ_NO )
AND
(
--PROPERTY.PRO_SCHEME = ( '00054' )
--AND
REPAIR_CURRENT.REP_RAISED_DATE BETWEEN '01-APR-2015' AND sysdate
AND
REPAIR_CURRENT.REP_STATUS <> 'CAN'
)
GROUP BY
PROPERTY.PRO_MANAGINGCOMPANY_DESCR,
PROPERTY.PRO_SCHEME_DESCR,
PROPERTY.PRO_SCHEME,
to_char(REPAIR_CURRENT.REP_RAISED_DATE,'Mon'),
to_number(to_char(to_date(REPAIR_CURRENT.REP_RAISED_DATE,'dd-mon-yy'),'mm'))
If you just want to get the beginning of the fiscal year for the current date:
SELECT TO_DATE('01-04' || CASE
WHEN EXTRACT(MONTH FROM SYSDATE) > 4 THEN
EXTRACT(YEAR FROM SYSDATE)
ELSE
EXTRACT(YEAR FROM SYSDATE)-1
END, 'DD-MM-RRRR') FISCAL_YEAR
FROM DUAL
This works for any date:
REPAIR_CURRENT.REP_RAISED_DATE
BETWEEN Add_Months(Trunc(Add_Months(sysdate,-3),'YYYY'),3)
AND Sysdate
Basically, subtract three months, truncate to the year, and add three months back on.
To just get the financial year for a date, use:
Extract(Year from Add_Months(Trunc(Add_Months(sysdate,-3),'YYYY'),3))
SELECT *
FROM your_table
WHERE datetime >= CASE
WHEN SYSDATE < TRUNC( SYSDATE, 'YEAR' ) + INTERVAL '3' MONTH
THEN TRUNC( SYSDATE, 'YEAR' ) - INTERVAL '9' MONTH
ELSE TRUNC( SYSDATE, 'YEAR' ) + INTERVAL '3' MONTH
END;
Thank you, the following worked! add_months(trunc(sysdate,'year'),3) AND sysdate
thank you all for your input :)
REPAIR_CURRENT.REP_RAISED_DATE BETWEEN '01-APR-2015' AND sysdate
Firstly, '01-APR-2015' is not a DATE it is a string. You must always use TO_DATE along with proper format model to explicitly convert the string into DATE. Or, use the ANSI Date literal as you are not concerned with the time portion. It uses a fixed format 'YYYY-MM-DD'.
Now, coming to your date arithmetic, you could use a CASE expression to evaluate the financial date depending on the year.
REP_RAISED_DATE
BETWEEN
CASE
WHEN
SYSDATE < ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 3)
THEN
ADD_MONTHS(TRUNC(SYSDATE, 'YEAR') , -9)
ELSE
ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 3)
END
AND SYSDATE
Basically, SYSDATE >= ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 3) is to check whether SYSDATE is greater than 1-APR of current year. And, SYSDATE < ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 15) is to check whether it is between JAN and MARCH of next year.
For example,
SQL> SELECT
2 CASE
3 WHEN
4 SYSDATE < ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 3)
5 THEN
6 ADD_MONTHS(TRUNC(SYSDATE, 'YEAR') ,-9)
7 ELSE
8 ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 3)
9 END FINANCIAL_YEAR
10 FROM dual;
FINANCIAL
---------
01-APR-15
For date between JAN and MAR of next year:
SQL> SELECT
2 CASE
3 WHEN
4 DATE '2016-02-01' < ADD_MONTHS(TRUNC(DATE '2016-02-01', 'YEAR'), 3)
5 THEN
6 ADD_MONTHS(TRUNC(DATE '2016-02-01', 'YEAR') ,-9)
7 ELSE
8 ADD_MONTHS(TRUNC(DATE '2016-02-01', 'YEAR'), 3)
9 END FINANCIAL_YEAR
10 FROM dual;
FINANCIAL
---------
01-APR-15
Following SQLreturns start and end date for Financial Year of current date.
SELECT
TO_DATE('01-04' || EXTRACT(YEAR FROM add_months(sysdate, -3)),'DD-MM-RRRR') from_dt ,
TO_DATE('31-03' || EXTRACT(YEAR FROM add_months(sysdate, 9)),'DD-MM-RRRR') to_dt from dual;
For any random date, you can use the following SQL: example for 01-04-2020
SELECT
TO_DATE('01-04' || EXTRACT(YEAR FROM add_months(to_date('01-04-2020','DD-MM-RRRR'), -3)),'DD-MM-RRRR') from_dt ,
TO_DATE('31-03' || EXTRACT(YEAR FROM add_months(to_date('01-04-2020','DD-MM-RRRR'), 9)),'DD-MM-RRRR') to_dt from dual;

In ORACLE get values from 01-01-YYYY to 12-31-YYYY previous year

In ORACLE I am trying to get values from PS_EMP_REVIEW_GOAL with a REVIEW_DT between 01-01-YYYY and 12-31-YYYY from last year.
I get the following error msg:
ORA-01843: not a valid month
01843. 00000 - "not a valid month"
*Cause:
*Action:
SELECT
ERG.REVIEW_DT,
ERG.CAREER_GOAL
from PS_EMP_REVIEW_GOAL ERG, PS_PERSONNEL P
where ERG.EMPLID = P.EMPLID
and ERG.REVIEW_DT = (Select max(ERG1.REVIEW_DT) from PS_EMP_REVIEW_GOAL ERG1
where ERG1.EMPLID = ERG.EMPLID
and ERG1.REVIEW_DT BETWEEN to_date('01-01-' || trunc(sysdate, 'YYYY'))-1
AND to_date('12-31-' || trunc(sysdate, 'YYYY'))-1
);
The problem is that TRUNC(SYSDATE, 'YYYY') will return whole date, which you then try to concatenate with day and month:
SELECT TRUNC(SYSDATE, 'YYYY') FROM dual;
TRUNC(SYSDATE,'YYYY')
---------------------
01-01-2013
What you should do instead is EXTRACT the year from SYSDATE and use the date format model to convert the string into a DATE:
SELECT TO_DATE('01-01-' || EXTRACT(YEAR FROM SYSDATE), 'MM-DD-YYYY') - 1 AS val
FROM dual;
VAL
----------
31-12-2012
So your code should look like this:
SELECT
ERG.REVIEW_DT,
ERG.CAREER_GOAL
from PS_EMP_REVIEW_GOAL ERG, PS_PERSONNEL P
where ERG.EMPLID = P.EMPLID
and ERG.REVIEW_DT = (Select max(ERG1.REVIEW_DT) from PS_EMP_REVIEW_GOAL ERG1
where ERG1.EMPLID = ERG.EMPLID
and ERG1.REVIEW_DT BETWEEN TO_DATE('01-01-' || EXTRACT(YEAR FROM SYSDATE), 'MM-DD-YYYY') - 1
AND TO_DATE('12-31-' || EXTRACT(YEAR FROM SYSDATE), 'MM-DD-YYYY') - 1
);
Edit If you want to compare the date with the dates from the previous year, you should move the - 1 inside the TO_DATE like this:
and ERG1.REVIEW_DT BETWEEN TO_DATE('01-01-' || (EXTRACT(YEAR FROM SYSDATE) - 1), 'MM-DD-YYYY')
AND TO_DATE('12-31-' || (EXTRACT(YEAR FROM SYSDATE) - 1), 'MM-DD-YYYY')
Another shorter option would be:
extract(year from ERG1.REVIEW_DT) = extract(year from current_date) - 1
BUT: this would not use an an index on ERG1.REVIEW_DT so it might be to slow for your purposes. IN that case Przemyslaw's answer is much better, because that expression can use an index on that column.
Something like this will implement the logic you're asking for
and ERG1.REVIEW_DT BETWEEN trunc(sysdate, 'YYYY')
AND add_months( trunc(sysdate, 'YYYY'), 12 ) - 1
Given that an Oracle DATE always has a day and a time component, though, this will exclude rows where review_dt is on 12/31 but after midnight. My guess is that you really want
and ERG1.REVIEW_DT >= trunc(sysdate, 'YYYY')
AND ERG1.REVIEW_DT < add_months( trunc(sysdate, 'YYYY'), 12 )