Current status based on week number ORACLE - sql

I got this query on order to get all the days from the first day of the year (01/01/2018) to the end of next year (31/12/2019).
SELECT MYDATE,
TO_CHAR(NR_OF_SUNDAYS + 1,'FM09') WEEK_NUM,
FROM
(
SELECT MYDATE,
( (TRUNC(MYDATE,'DAY') - TRUNC(TRUNC(MYDATE,'YYYY'),'DAY')) / 7 ) +
CASE WHEN TO_CHAR(TRUNC(MYDATE,'YYYY'),'DAY') = 'SUN' THEN 1 ELSE 0 END AS NR_OF_SUNDAYS
FROM
( SELECT TRUNC (SYSDATE, 'YY') - 1 + LEVEL AS MYDATE
FROM DUAL
CONNECT BY LEVEL <= TRUNC (ADD_MONTHS (SYSDATE, 24), 'YY') -
TRUNC (SYSDATE, 'YY')
)
)
I need a column that specifies the following cases:
1) CASE WHEN MYDATE < TO_CHAR(SYSDATE, 'DD/MM/YYYY') THEN 'PAST DUE'
(this works its easy and no problem)
2) if my current =< mydate
week_num then 'CURRENT WEEK'(Excluding PAST DUE)
3) if my current week + one week then
'NEXT WEEK' (Excluding PAST DUE)
4) else FUTURE
Thanks a lot for your help.

So, in my answer I tried retain the logic behind your week number calculation.
However keep in mind that you could calculate week number using oracle to_char(date,'WW'), to_char(date,'IW'), to_char(date,'W') functions and then your life would be easier.
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.
Having said all that here is my solution that uses only sql (note that defining and using a function would be a lot easier), based on your calculation method.
with date_table as (
SELECT MYDATE, to_number(TO_CHAR(NR_OF_SUNDAYS + 1,'FM09')) WEEK_NUM, to_number(to_char(MYDATE+1,'IW')) as nu
FROM
(
SELECT MYDATE,
( (TRUNC(MYDATE,'DAY') - TRUNC(TRUNC(MYDATE,'YYYY'),'DAY')) / 7 ) +
CASE WHEN TO_CHAR(TRUNC(MYDATE,'YYYY'),'DY', 'NLS_DATE_LANGUAGE = american') = 'SUN' THEN 1 ELSE 0 END AS NR_OF_SUNDAYS
FROM
( SELECT TRUNC (SYSDATE, 'YY') - 1 + LEVEL AS MYDATE
FROM DUAL
CONNECT BY LEVEL <= TRUNC (ADD_MONTHS (SYSDATE, 24), 'YY') -TRUNC (SYSDATE,'YY')
)
)
),
todays_week as
(
select distinct WEEK_NUM from date_table
where trunc(sysdate)=trunc(mydate)
),
pre_final as (
select MYDATE,WEEK_NUM, (select WEEK_NUM from todays_week) as todaysweek from date_table)
select MYDATE,sysdate,WEEK_NUM,todaysweek,
case when trunc(MYDATE) < trunc(sysdate) then 'PAST DUE'
when todaysweek = WEEK_NUM and abs(MYDATE-sysdate)<=7 then 'CURRENT WEEK'
when todaysweek +1 = WEEK_NUM and abs(MYDATE-sysdate)<=14 then 'Next Week'
else 'Future' end as description
from pre_final;
The main idea is to find today's week number and then use case when.
Here is my fiddle link with the results.
http://sqlfiddle.com/#!4/3149e4/148
EDIT 1:
Now, similar results one could achive with something like this:
select res.*,
case when trunc(MYDATE) < trunc(sysdate) then 'PAST DUE'
when todaysweek = WEEK_NUM and abs(MYDATE-sysdate)<=7 then 'CURRENT WEEK'
when todaysweek +1 = WEEK_NUM and abs(MYDATE-sysdate)<=14 then 'Next Week'
else 'Future' end as description
from (
SELECT MYDATE, to_number(to_char(MYDATE,'IW')) as WEEK_NUM,to_number(to_char(sysdate,'IW')) as todaysweek
FROM
( SELECT TRUNC (SYSDATE, 'YY') - 1 + LEVEL AS MYDATE
FROM DUAL
CONNECT BY LEVEL <= TRUNC (ADD_MONTHS (SYSDATE, 24), 'YY') -TRUNC (SYSDATE,'YY')
)) res

Related

How to generate the first day of the week, the last day of the week and week number between two dates in Oracle

I would like to insert in table :
the first day of the week starting from Monday.
the last day of the week as Sunday.
the WEEK number => (1-52 or 1-53) based on the ISO standard.
First i tried to select first day, the last day and week number for specific date and it's works :
WITH ranges AS
(
SELECT to_date('29-10-2012', 'dd-MM-yyyy') AS DATE_TEST FROM DUAL
)
SELECT DATE_TEST "DATE",
TO_CHAR( NEXT_DAY( TRUNC(DATE_TEST) , 'SUNDAY' )) "WEEK END DATE",
TO_CHAR(TO_DATE(DATE_TEST,'DD-MON-YYYY'),'WW')+1 "WEEK NUMBER"
FROM ranges ;
But now i would like to display this data between two dates, but i get result only for the start_date. someone can help please.
after, when all good i will insert all in the table.
Thanks
WITH ranges AS(
select to_date('29-OCT-2012', 'dd-MM-yyyy') START_DATE,
to_date('31-DEC-2016', 'dd-MM-yyyy') END_DATE
from dual
)
SELECT START_DATE "DATE",
TO_CHAR( NEXT_DAY( TRUNC(START_DATE) , 'SUNDAY' )) "WEEK END DATE",
TO_CHAR(TO_DATE(START_DATE,'DD-MON-YYYY'),'WW')+1 "WEEK NUMBER"
FROM ranges ;
Format WW returns 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, see Datetime Format Elements
In order to get the week number according to ISO-8601 standard use format IW. I would suggest like this:
WITH ranges AS(
SELECT
DATE '2012-10-29' START_DATE,
DATE '2016-12-31' END_DATE
FROM dual
)
SELECT
START_DATE, END_DATE,
TRUNC(START_DATE + 7*(LEVEL-1), 'IW') AS Week_Start_Date,
TRUNC(START_DATE + 7*(LEVEL-1), 'IW') + 6 AS Week_End_Date,
TO_CHAR(TRUNC(START_DATE + 7*(LEVEL-1)), 'IYYY-"W"IW') WEEK_NUMBER
FROM ranges
CONNECT BY START_DATE + 7*(LEVEL-1) <= END_DATE;
Looks like you're looking for a calendar.
Based on your RANGES CTE, there's another - calendar which utilizes hierarchical query to create all dates between start_date and end_date. Once you have all dates, extract values you're interested in.
SQL> with
2 ranges as
3 (select to_date('29-OCT-2012', 'dd-MM-yyyy') start_date,
4 to_date('31-DEC-2016', 'dd-MM-yyyy') end_date
5 from dual
6 ),
7 calendar as
8 (select start_date + level - 1 as datum
9 from ranges
10 connect by level <= end_date - start_date + 1
11 )
12 select
13 min(datum) start_date,
14 min(next_day(datum, 'sunday')) week_end_date,
15 to_char(datum, 'ww') week_number
16 from calendar
17 group by to_char(datum, 'yyyy'), to_char(datum, 'ww')
18 order by 1;
START_DATE WEEK_END_D WE
---------- ---------- --
29-10-2012 04-11-2012 44
04-11-2012 11-11-2012 45
11-11-2012 18-11-2012 46
18-11-2012 25-11-2012 47
25-11-2012 02-12-2012 48
<snip>
09-12-2016 11-12-2016 50
16-12-2016 18-12-2016 51
23-12-2016 25-12-2016 52
30-12-2016 01-01-2017 53
222 rows selected.
SQL>
How are you?
to help, I tried to do some research, I found these links.
enter link description here
enter link description here
I found:
SELECT
ROUND((TRUNC(SYSDATE) - TRUNC(SYSDATE, 'YEAR')) / 7,0) CANTWEEK,
NEXT_DAY(SYSDATE, 'SUNDAY') - 7 FIRSTDAY,
NEXT_DAY(SYSDATE, 'SUNDAY') - 1 LASTDAY
FROM DUAL
and
select
to_char(sysdate - to_char(sysdate, 'd') + 2, 'yyyymmdd') first_day_of_week
, to_char(sysdate - to_char(sysdate, 'd') + 8, 'yyyymmdd') last_day_of_week
from
dual
and
select sysdate AS today,
TRUNC(next_day(sysdate,'MONDAY')-8) as DOMINGO,
TRUNC(next_day(sysdate,'SATURDAY')) as SABADO
from dual
I don't have oracle here so I couldn't test it well but it should solve what you need, anything let me know :)
Here is a way to make the common table expression return a range of dates.
with ranges (dt) as (
select to_date('29-OCT-2012', 'dd-MM-yyyy') as dt
from dual
union all
select ranges.dt+1
from ranges
where ranges.dt < to_date('31-DEC-2016', 'dd-MM-yyyy')
)
Then you can use that to calculate the other values.
SELECT dt "DATE"
, TO_CHAR(NEXT_DAY(TRUNC(dt), 'SUNDAY')) "WEEK END DATE"
, TO_CHAR(TO_DATE(dt,'DD-MON-YYYY'),'WW') + 1 "WEEK NUMBER"
, cast(TO_CHAR(dt, 'WW') as int) +
case when cast(TO_CHAR(dt, 'D') as int) < cast(TO_CHAR(trunc(dt, 'year'), 'D') as int) then 1 else 0 end WeekNumberInYear
FROM ranges ;
If you want to have all of your date calculations done at once, check out an example here: https://dbfiddle.uk/?rdbms=oracle_18&fiddle=35e407af3b5bf711bb7ae53b8cf0e608

oracle query to report data only for the 1st or 2nd half of the year

I have a report which should display enrollment data only within 2 date ranges Jan-June or July-dec depending on current date.
Scenarios:
If the current date is 042020 then I should display enrollement data between this range: 072019-122019
If the current date is 072020 then I should display enrollement data between this range: 012020-062020
If the current date is 022021 then I should display enrollement data between this range: 072020-122020
Current query reports everything past 6 months with his query.
select * from enrollement where enrollement_dt > add_months(sysdate - 6);
Is there any function available in oracle to do the same or how do i get the logic in a single statement?
Any help with this is highly appreciated.
You may try below query -
select *
from enrollement
WHERE TO_CHAR(enrollement_dt, 'MMYYYY') >= CASE WHEN TO_CHAR(SYSDATE, 'mm') <= '06'
THEN TO_DATE('07' || EXTRACT(YEAR FROM SYSDATE) - 1, 'MMYYYY')
ELSE THEN TO_DATE('01' || EXTRACT(YEAR FROM SYSDATE), 'MMYYYY')
END
AND TO_CHAR(enrollement_dt, 'MMYYYY') <= CASE WHEN TO_CHAR(SYSDATE, 'mm') <= '06'
THEN TO_DATE('12' || EXTRACT(YEAR FROM SYSDATE) - 1, 'MMYYYY')
ELSE THEN TO_DATE('06' || EXTRACT(YEAR FROM SYSDATE), 'MMYYYY')
END
Basically you want to truncate to the half-year. But Oracle doesn't support this.
One method counts half-years and compares them. You want the previous half year from the current date. That would be:
select (extract(year from sysdate) * 2 + floor(extract(month from sysdate) - 1) / 6) - 1
from dual
You can use this same formula:
where (extract(year from enrollement_dt) * 2 + floor(extract(month from enrollement_dt) - 1) / 6) - 1 =
extract(year from sysdate) * 2 + floor(extract(month from sysdate) - 1) / 6) - 1
)
from dual;
Unfortunately that can't use an index on the column. So, we can revisit this. You can get the first day of the current half using some date arithmetic:
select trunc(sysdate, 'Q') - mod(floor((extract(month from sysdate) - 1) / 3), 2) * interval '3' month
from dual
That just needs to be plugged into a where clause:
where enrollement_dt >= trunc(sysdate, 'Q') - mod(floor((extract(month from sysdate) - 1) / 3), 2) * interval '3' month - interval '6' month and
enrollement_dt < trunc(sysdate, 'Q') - mod(floor((extract(month from sysdate) - 1) / 3), 2) * interval '3' month
Voila! An expression that can even use an index.
You can use the below to get the start date and end date for enrollment
WITH data
AS (SELECT TRUNC(SYSDATE) curr_date from dual
),
d2
AS (SELECT curr_date,
To_date('0107'
||( Extract (year FROM curr_date) - 1 ), 'ddmmyyyy')
start_first_half,
To_date('3112'
||( Extract (year FROM curr_date) - 1 ), 'ddmmyyyy')
end_first_half,
To_date('0101'
||Extract (year FROM curr_date), 'ddmmyyyy')
start_second_half,
To_date('3006'
||Extract (year FROM curr_date), 'ddmmyyyy')
end_second_half
FROM data)
SELECT curr_date,
CASE
WHEN To_char(curr_date, 'MM') >= To_char(start_first_half, 'MM')
AND To_char(curr_date, 'MM') <= To_char(end_first_half, 'MM') THEN
start_second_half
ELSE start_first_half
END start_date1,
CASE
WHEN To_char(curr_date, 'MM') >= To_char(start_first_half, 'MM')
AND To_char(curr_date, 'MM') <= To_char(end_first_half, 'MM') THEN
end_second_half
ELSE end_first_half
END end_date1
FROM d2
You can use it in your query like below
Select * from enrollment_table a, (WITH data
AS (SELECT TRUNC(SYSDATE) curr_date from dual
),
d2
AS (SELECT curr_date,
To_date('0107'
||( Extract (year FROM curr_date) - 1 ), 'ddmmyyyy')
start_first_half,
To_date('3112'
||( Extract (year FROM curr_date) - 1 ), 'ddmmyyyy')
end_first_half,
To_date('0101'
||Extract (year FROM curr_date), 'ddmmyyyy')
start_second_half,
To_date('3006'
||Extract (year FROM curr_date), 'ddmmyyyy')
end_second_half
FROM data)
SELECT curr_date,
CASE
WHEN To_char(curr_date, 'MM') >= To_char(start_first_half, 'MM')
AND To_char(curr_date, 'MM') <= To_char(end_first_half, 'MM') THEN
start_second_half
ELSE start_first_half
END start_date1,
CASE
WHEN To_char(curr_date, 'MM') >= To_char(start_first_half, 'MM')
AND To_char(curr_date, 'MM') <= To_char(end_first_half, 'MM') THEN
end_second_half
ELSE end_first_half
END end_date1
FROM d2 ) b
where a.enrollment_date >=b.start_date1
and a.enrollment_date <=b.end_date1

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

get second and fourth saturday along with all sundays of the previous month in oracle

I have the following query which gives the second and fourth Saturdays of the previous month along with all the Sundays of the previous month:
SELECT to_char(NEXT_DAY(NEXT_DAY(NEXT_DAY(NEXT_DAY(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1, 'SATURDAY'), 'SATURDAY'),'SATURDAY'),'SATURDAY'),'YYYYMMDD') SECOND_SATURDAY
FROM DUAL
UNION ALL
SELECT to_char(NEXT_DAY(NEXT_DAY(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1, 'SATURDAY'),'SATURDAY'),'YYYYMMDD') SECOND_SATURDAY
FROM DUAL
UNION ALL
select distinct day_date from
(SELECT to_char(NEXT_DAY(LEVEL + TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1,'SUNDAY'),'YYYYMMDD') day_date
FROM DUAL
CONNECT BY LEVEL <= ADD_MONTHS(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH'), 1) - TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH'))
where substr(day_date,1,6) in (select to_char((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL),'YYYYMM') from dual)
But I feel there must be a simpler way to get the same result in oracle.Any help in this regard is welcome. My requirement for the date format is 'YYYYMMDD'.
Edited because I misunderstood the question:
I think you want something like the following:
SELECT TO_CHAR(my_date, 'YYYYMMDD') AS my_formatted_date
FROM (
SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2))+7, 'SATURDAY') AS my_date
FROM dual
UNION ALL
SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2))+21, 'SATURDAY')
FROM dual
UNION ALL
SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY') + (LEVEL-1)*7
FROM dual
CONNECT BY NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY') + (LEVEL-1)*7 < TRUNC(SYSDATE, 'MONTH')
);
In the first part of the query I determine the last day of the previous month and then get the first Saturday that falls after at least one week after that date (the second Saturday of the month will be anywhere from the 8th to the 14th). Then I get the first Saturday falling at least three weeks after the last day of the previous month (the fourth Saturday will be anywhere from the 22nd to the 28th). Last, I loop over the Sundays of the previous month, starting from the first Sunday falling after the last day of the month previous to that (that is, two months ago). You could also use NEXT_DAY(TRUNC(ADD_MONTHS(SYSDATE, -1) - 1), 'SUNDAY') instead of NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY')
MY_FORMA
--------
20190209
20190223
20190203
20190210
20190217
20190224
6 rows selected.
For instance like here:
with
t1 as (select add_months(trunc(sysdate, 'month'), -1) dt from dual),
t2 as (
select dt + level - 1 dt, to_char(dt + level - 1, 'dy', 'nls_date_language=english') dy
from t1 connect by dt + level - 1 < trunc(sysdate, 'month'))
select to_char(dt, 'yyyymmdd') dt, dy
from (
select dt, dy, sum(case when dy = 'sat' then 1 end) over (order by dt) sm from t2)
where dy = 'sun' or (dy = 'sat' and sm in (2, 4))
Result:
DT DY
-------- ---
20190203 sun
20190209 sat
20190210 sun
20190217 sun
20190223 sat
20190224 sun
I generated all days for previous month, assigned english day names, conditionally counted saturdays and showed only interesting dates.
Edit:
This works but is there any way to get around the with clause since my
parent query is of the from: with x as ( .... where date in ("required
days") and ...) . So it presents a nested with situation.
Yes, you can convert it easily, for example like here:
select to_char(dt, 'yyyymmdd') dt
from (
select dt, dn, rank() over (order by mod(dn, 6), dt) rnk
from (
select d + level - 1 dt, d + level - trunc(d + level - 1, 'iw') dn
from (select add_months(trunc(sysdate, 'month'), -1) d from dual)
connect by level <= add_months(d, 1) - d))
where dn = 7 or (dn = 6 and rnk in (2, 4))
dbfiddle demo
with clause made steps more readable. Now I also used day numbers and mod() for counting, just to show different approaches, but you can use whatever is clearer for you (day names, sum or count instead of rank).

Next business day (Monday - Friday) in Oracle?

I need to calculate the next business day (business days being Monday - Friday) in Oracle. At the moment in our reporting program we use a variable it supports <|Tomorrow|> but the problem is that customers do not receive the require details for say a Monday's delivery until a Sunday which is pointless since no one is there.
So we need to calculate Monday on the previous Friday, Tuesday on Monday, Wednesday on Tuesday, Thursday on Wednesday and Friday on Thursday.
What is the best method to do it within directly Oracle since our reporting program does not seem to have a next business day variable. Basically we need to change Where ORDER_HEADER.DELIVERY_DATE = '<|Tomorrow|>' to Where ORDER_HEADER.DELIVERY_DATE = ** next business day **
This is Oracle 10g.
Select ORDER_HEADER.DELIVERY_DATE As "Delivery Date",
ORDER_HEADER.ORDER_NO As "Document No",
ORDER_HEADER.CUSTOMER_ORDER_NO As "Customer Order No",
ORDER_TOTALS.ORDER_TOTAL_QUANTITY As "Total Items",
ORDER_TOTALS.ORDER_TOTAL_NET As "Total Net"
From ORDER_HEADER
Inner Join ORDER_TOTALS On ORDER_HEADER.ORDER_NO = ORDER_TOTALS.ORDER_NO
Where ORDER_HEADER.DELIVERY_DATE = '<|Tomorrow|>' And ORDER_HEADER.CUSTOMER_NO = :Param1
Order By "Document No"
These things are normally done with a table that lists all the working days in a year rather than a naive formula like:
CASE WHEN (1 + TRUNC (SYSDATE) - TRUNC (SYSDATE, 'IW')) < 5
THEN 1 + (1 + TRUNC (SYSDATE) - TRUNC (SYSDATE, 'IW'))
ELSE 1
END --(on monday to thursday this returns 2 to 5, on fri/sat/sun this returns 1)
CASE WHEN (1 + TRUNC (SYSDATE) - TRUNC (SYSDATE, 'IW')) < 5
THEN TRUNC (SYSDATE) + 1
ELSE TRUNC (SYSDATE + 4), 'IW')
END --(on monday to thursday this returns tomorrow's date, on fri/sat/sun it returns next monday's date)
Using a table allows you to factor in things like bank holidays, national holidays, religious festivals, voting days, mourning days, ad hoc days off that may occur for company, or political reasons etc etc. Maintaining the table then becomes an important task. Retrieving the next working day is essentially a case of querying the table for the MIN(date) WHERE date > current_date
A typical method would be:
WHERE ( (to_char(sysdate, 'dy') in ('sun', 'mon', 'tue', 'wed', 'thu') and oh.DELIVERY_DATE = TRUNC(SYSDATE) + 1
) or
(to_char(sysdate, 'dy') in ('sat') and oh.DELIVERY_DATE = TRUNC(SYSDATE) + 2
) or
(to_char(sysdate, 'dy') in ('fri') and oh.DELIVERY_DATE = TRUNC(SYSDATE) + 3
)
)
I strongly agree with the other answer that you should have a calendar table for your business. The next business day is not only about weekends but also about holidays.
If you looking for only week days, then one way is create your own function which returns next business day:
create or replace function calc_date(dt date)
return date as ret date;
begin
SELECT min(dt) into ret from (
SELECT ( dt + 1 ) AS dt FROM DUAL
UNION
SELECT ( dt + 2 ) AS dt FROM DUAL
UNION
SELECT ( dt + 3 ) AS dt FROM DUAL
) t
where TO_CHAR(dt, 'D') not in (1,7);
return ret;
end;
Call
select calc_date('2017-09-08') from dual;