Get particular date from dual - oracle [closed] - sql

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
i want create oracle query using dual to pickup the correct business day
condition:
if 1st day of the month falls on sunday or monday then it need to choose tuesday date

So, if 1st day of month is Sunday or Monday, you want to return the next Tuesday. For all other days, you want to return that day.
Just to set the environment (you don't have to do that):
SQL> alter session set nls_date_language = 'english';
Session altered.
SQL> alter session set nls_date_format = 'dd.mm.yyyy, dy';
Session altered.
Asterisk marks months which reflect the requirement.
SQL> with
2 temp (sys_date) as
3 -- it simulates 15th day of each month in 2021; something what SYSDATE would return
4 (select add_months(date '2021-01-15', level - 1)
5 from dual
6 connect by level <= 12),
7 day (sys_date, day) as
8 -- day name
9 (select sys_date,
10 to_char(trunc(sys_date, 'mm'), 'dy')
11 from temp
12 )
13 select trunc(t.sys_date, 'mm') first_day_of_month,
14 --
15 case when d.day in ('sun', 'mon') then next_day(trunc(t.sys_date, 'mm'), 'tue')
16 else trunc(t.sys_date, 'mm')
17 end result
18 from day d join temp t on trunc(d.sys_date, 'mm') = trunc(t.sys_date, 'mm');
FIRST_DAY_OF_MO RESULT
--------------- --------------------
01.01.2021, fri 01.01.2021, fri
01.02.2021, mon 02.02.2021, tue *
01.03.2021, mon 02.03.2021, tue *
01.04.2021, thu 01.04.2021, thu
01.05.2021, sat 01.05.2021, sat
01.06.2021, tue 01.06.2021, tue
01.07.2021, thu 01.07.2021, thu
01.08.2021, sun 03.08.2021, tue *
01.09.2021, wed 01.09.2021, wed
01.10.2021, fri 01.10.2021, fri
01.11.2021, mon 02.11.2021, tue *
01.12.2021, wed 01.12.2021, wed
12 rows selected.
SQL>
In reality, you'd need a simpler version:
SQL> select case when to_char(trunc(sysdate, 'mm'), 'dy') in ('sun', 'mon') then next_day(trunc(sysdate, 'mm'), 'tue')
2 else trunc(sysdate, 'mm')
3 end result
4 from dual;
RESULT
--------------------
01.10.2021, fri
SQL>

if 1st day of the month falls on sunday or monday then it need to choose tuesday date
As I understand it, if the first day of the current month is either Sunday or Monday then you want to return Tuesday of the current week; otherwise return the current day:
SELECT CASE
WHEN TRUNC(SYSDATE, 'MM') - TRUNC(TRUNC(SYSDATE, 'MM'), 'IW')
IN (0, 6)
THEN TRUNC(SYSDATE) - (TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')) + 1
ELSE TRUNC(SYSDATE)
END
FROM DUAL;
Note: this will work in any territory or language.

Related

How to get previous working date using trunc(sysdate) in oracle

Greetings for the day!
i have written a python script that will run a select query using oracle database and will share the result with users based on the result it gets from that query. My aim is to run it through task scheduler on which it should automatically adjust the date mentioned in sql query and should always pick the last business day means if its monday, it should run the query with asof day as friday, if tuesday then asod day as Monday and so on.
Note : the report in the query runs on T+1 basis means if asof date is 21st Apr 2022 means it's actual start time would be 22 Apr 2022, so when it will run on 25th Apr (Monday) the asof date would be 22nd Apr
select* from snap_states
where asof = trunc(sysdate)-1
and upper(system) like ('LOANSL%')
order by start_time;***
If you're skipping weekends, then you could
SQL> with datum (sys_date) as
2 (select date '2022-04-23' from dual union all -- Saturday
3 select date '2022-04-24' from dual union all -- Sunday
4 select date '2022-04-25' from dual union all -- Monday
5 select date '2022-04-26' from dual -- Tuesday
6 )
7 select to_char(sys_date, 'dd.mm.yyyy, Dy') sys_date,
8 trunc(sys_date - case to_char(sys_date, 'Dy', 'nls_date_language = english')
9 when 'Sun' then 2
10 when 'Mon' then 3
11 else 1
12 end) as prev_work_day
13 from datum;
SYS_DATE PREV_WORK_
------------------------ ----------
23.04.2022, Sat 22.04.2022
24.04.2022, Sun 22.04.2022
25.04.2022, Mon 22.04.2022
26.04.2022, Tue 25.04.2022
SQL>
Applied to your query:
select *
from snap_states
where asof = trunc(sysdate - case to_char(sysdate, 'Dy', 'nls_date_language = english')
when 'Sun' then 2
when 'Mon' then 3
else 1
end)
and upper(system) like 'LOANSL%'
order by start_time;

How to call a dynamic day in sql?

I have a table I want to pull all date records before the most recent Friday. I know you can use sysdate (or getdate) to pull the current day, but all the solutions to similar questions I've looked at explicitly specify the numeric day of the week in the query. Todays Thursday so the below would work, but is there a dynamic alternative to this?
SELECT *
FROM table
WHERE datefield < sysdate - 6
You could use:
SELECT NEXT_DAY(TRUNC(SYSDATE) - 7, 'FRIDAY') AS last_friday
FROM DUAL;
However, if someone tries to query the data and is using a different language then you will get an error. I.e.:
ALTER SESSION SET NLS_DATE_LANGUAGE = 'FRENCH';
SELECT NEXT_DAY(TRUNC(SYSDATE) - 7, 'FRIDAY') AS last_friday
FROM DUAL;
Outputs:
ORA-01846: not a valid day of the week
A solution that works regardless of the language is to compare the day to the start of the ISO week (which is always a Monday):
SELECT TRUNC(SYSDATE, 'IW')
+ CASE WHEN SYSDATE - TRUNC(SYSDATE, 'IW') < 5
THEN -3
ELSE +4
END AS last_friday
FROM DUAL;
Outputs (with the NLS_DATE_FORMAT set to YYYY-MM-DD HH24:MI:SS (DY)):
LAST_FRIDAY
2022-01-14 00:00:00 (FRI)
db<>fiddle here
Your query would be:
SELECT *
FROM table
WHERE datefield < TRUNC(SYSDATE, 'IW')
+ CASE WHEN SYSDATE - TRUNC(SYSDATE, 'IW') < 5
THEN -3
ELSE +4
END
next_day function might help.
SQL> with test (datum) as
2 -- sample data; this January up to today
3 (select trunc(sysdate, 'mm') + level - 1
4 from dual
5 connect by level <= 20
6 )
7 select to_char(datum, 'dd.mm.yyyy, dy') datum
8 from test
9 where datum < next_day(sysdate - 7, 'FRIDAY')
10 order by datum;
DATUM
------------------------
01.01.2022, sat
02.01.2022, sun
03.01.2022, mon
04.01.2022, tue
05.01.2022, wed
06.01.2022, thu
07.01.2022, fri
08.01.2022, sat
09.01.2022, sun
10.01.2022, mon
11.01.2022, tue
12.01.2022, wed
13.01.2022, thu
14.01.2022, fri
14 rows selected.
SQL>

Oracle SQL get First Business Day date of given date

How can i get the date of the first business day of a given date .
For example:
01-AUG-21 is Sunday, so the first business day is 02-AUG-21 .
You can use a simple case statement in SQL or PL/SQL. In the example below, just replace SYSDATE + LEVEL with the date you would like to use.
SELECT SYSDATE + LEVEL AS some_date,
TO_CHAR (SYSDATE + LEVEL, 'DY') AS some_day_of_week,
SYSDATE
+ LEVEL
+ CASE TO_CHAR (SYSDATE + LEVEL, 'DY') WHEN 'SAT' THEN 2 WHEN 'SUN' THEN 1 ELSE 0 END AS business_day
FROM DUAL
CONNECT BY LEVEL <= 14;
SOME_DATE SOME_DAY_OF_WEEK BUSINESS_DAY
____________ ___________________ ________________
02-JUL-21 FRI 02-JUL-21
03-JUL-21 SAT 05-JUL-21
04-JUL-21 SUN 05-JUL-21
05-JUL-21 MON 05-JUL-21
06-JUL-21 TUE 06-JUL-21
07-JUL-21 WED 07-JUL-21
08-JUL-21 THU 08-JUL-21
09-JUL-21 FRI 09-JUL-21
10-JUL-21 SAT 12-JUL-21
11-JUL-21 SUN 12-JUL-21
12-JUL-21 MON 12-JUL-21
13-JUL-21 TUE 13-JUL-21
14-JUL-21 WED 14-JUL-21
15-JUL-21 THU 15-JUL-21
Here is a PL/SQL example of the same logic
DECLARE
FUNCTION get_business_day (p_date DATE)
RETURN DATE
IS
BEGIN
RETURN TRUNC (
p_date
+ CASE TO_CHAR (p_date, 'DY')
WHEN 'SAT' THEN 2
WHEN 'SUN' THEN 1
ELSE 0
END);
END;
BEGIN
DBMS_OUTPUT.put_line (get_business_day (p_date => SYSDATE));
END;
/
Here's one option: as it is only about 1 week, create a little one-week-calendar and fetch date which is larger than the one entered as a parameter, and which isn't a weekend.
with little_calendar as
(select to_date(:par_datum, 'dd.mm.yyyy') + level - 1 datum
from dual
connect by level <= 7
)
select min(datum)
from little_calendar
where datum > to_date(:par_datum, 'dd.mm.yyyy')
and to_char(datum, 'dy', 'nls_date_language = english')
not in ('sat', 'sun');
A few examples in SQL*Plus:
SQL> with little_calendar as
2 (select to_date('&&par_datum', 'dd.mm.yyyy') + level - 1 datum
3 from dual
4 connect by level <= 7
5 )
6 select min(datum)
7 from little_calendar
8 where datum > to_date('&&par_datum', 'dd.mm.yyyy')
9 and to_char(datum, 'dy', 'nls_date_language = english')
10 not in ('sat', 'sun');
Enter value for par_datum: 01.07.2021 --> the 1st working day after 01.07.2021 (Thursday) ...
MIN(DATUM)
---------------
02.07.2021, fri --> ... is 02.07.2021 (Friday)
SQL> undefine par_datum
SQL> /
Enter value for par_datum: 02.07.2021 --> working day that follows 02.07.2021 (Friday) ...
MIN(DATUM)
---------------
05.07.2021, mon --> ... is 05.07.2021 (Monday)
SQL>

Problem with getting the quarter from a date in Oracle

I've written a query to get the start date of the quarters from current year and previous year by using the sysdate.
eg. Today falls in the 1st quarter of the year, therefore I only want to get the start date of 1st quarter of last year and this year.
If I'm on December (which is in the 4th quarter), I want to get the start dates of 8 quarters (4 from last year, 4 from this year.)
select b.dt,
to_number(to_char(SYSDATE, 'Q')),
to_number(to_char(b.dt, 'Q'))
from dual a,
(select add_months(trunc(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -12),
'yyyy'),
(rownum - 1) * 3) dt
from all_objects
where rownum <= 8
and add_months(trunc(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -12),
'yyyy'),
(rownum - 1) * 3) <= SYSDATE
and to_number(to_char(SYSDATE, 'Q')) >=
to_number(to_char(add_months(trunc(ADD_MONTHS(TRUNC(SYSDATE,
'MM'),
-12),
'yyyy'),
(rownum - 1) * 3),
'Q'))) b
This query only returns the start date of 1st quarter of last year. I expect to get the start date of the 1st quarter of this year as well.
Here's one option; see comments within the code.
SQL> alter session set nls_date_format = 'dd.mm.yyyy';
Session altered.
SQL> with
2 -- this mimics SYSDATE
3 today (datum) as
4 (select date '&date_literal' from dual),
5 -- which quarter does DATUM belong to? Find 1st day in "this" and "previous" year
6 quart as
7 (select trunc(datum, 'yyyy') this,
8 trunc(add_months(datum, -12), 'yyyy') previous,
9 to_char(datum, 'q') quart from today)
10 -- the fina result
11 select add_months(this, (level - 1) * 3) result
12 from quart
13 connect by level <= quart
14 union all
15 select add_months(previous, (level - 1) * 3) result
16 from quart
17 connect by level <= quart;
Enter value for date_literal: 2019-03-24
RESULT
----------
01.01.2019
01.01.2018
SQL> /
Enter value for date_literal: 2019-08-13
RESULT
----------
01.01.2019
01.04.2019
01.07.2019
01.01.2018
01.04.2018
01.07.2018
6 rows selected.
SQL>

Oracle query to get end of week from the given data set

I have table in Oracle , where EOW columns indicate the end of week.
I want to write a query to get the nearest end of week date.
Table Cal
DAY DAY OFTHE WEEK EOW
20181026 FRI Y
20181027 SAT N
20181028 SUN N
20181029 MON N
20181030 TUE N -->
20181031 WED N
20181101 THU N
20181102 FRI Y -->
20181103 SAT N
So when I
select DAY , "logic" from cal where day = 20181030;
What should be "logic" so that I get the nearest end of week date , in this case
20181026.
Please help!!
Do you really need a fixed table for that? A CTE can easily create any calendar you want, so - I took that freedom to produce something like this.
I wrote it step-by-step so that you could follow its execution. Start from the first CTE (dates), then go to day_diff, and so forth). It seems that you are selecting the first FRI that precedes current date. Because, for 20181030, the nearest end-of-week isn't 20181026 (4 days to that Friday) but 20181102 (3 days to that Friday).
At the end, the result is
SQL> with dates as
2 (select
3 -- add "level" (sequence of numbers from 1 to 60) to 1st of previous month
4 trunc(add_months(sysdate, - 1), 'mm') + level - 1 datum,
5 -- convert that date into a day name (MON, FRI, ...)
6 to_char(trunc(add_months(sysdate, -1), 'mm') + level - 1, 'DY',
7 'NLS_DATE_LANGUAGE=ENGLISH') dan,
8 -- if day name is FRI, set EOW = Y. Else, it is N
9 case when to_char(trunc(add_months(sysdate, -1), 'mm') + level - 1, 'DY',
10 'NLS_DATE_LANGUAGE=ENGLISH') = 'FRI' then 'Y'
11 else 'N'
12 end eow
13 from dual
14 connect by level <= 60 -- my CTE will have 60 dates; yours can have any number
15 ),
16 day_diff as
17 (select datum, dan, eow,
18 datum - to_date('&par_datum', 'dd.mm.yyyy') diff
19 from dates
20 ),
21 diff_only_eow as
22 (select datum, dan, eow, diff,
23 row_number() over (order by diff desc) rn
24 from day_diff
25 where eow = 'Y'
26 and diff <= 0
27 )
28 select datum, dan, eow, diff, rn
29 from diff_only_eow
30 where rn = 1;
Enter value for par_datum: 30.10.2018
DATUM DAN E DIFF RN
-------- ------------ - ---------- ----------
20181026 FRI Y -4 1
SQL>
What I am guessing is,
If the date is 30-OCT-2018 (20181030), then you want last friday date as 26-OCT - 2018 (20181026).
Another Scenario :
If the date is 27-OCT-2018 (20181027), in that case also you want last friday date which is 26-OCT - 2018 (20181026).
If my this is guess is true then below query may work :
WITH TEMP1 AS
(
SELECT TO_CHAR(
TO_DATE('20181030','YYYYMMDD') ,'DD-MON-YY') AS DATE_TEST
FROM DUAL
)
SELECT next_day (TO_DATE(DATE_TEST,'DD-MON-YY')-7,'FRIDAY') Last_Friday
FROM TEMP1;
It will display output as :
LAST_FRIDAY
26-OCT-18
Which you can convert later in your required format.
Test Case 2
WITH TEMP1 AS
(
SELECT TO_CHAR(
TO_DATE('20181103','YYYYMMDD') ,'DD-MON-YY') AS DATE_TEST
FROM DUAL
)
SELECT next_day (TO_DATE(DATE_TEST,'DD-MON-YY')-7,'FRIDAY') Last_Friday
FROM TEMP1;
Output :
LAST_FRIDAY
02-NOV-18
Now breaking of above query :
WITH clause is used in CTE.
WITH TEMP1 AS
(
SELECT TO_CHAR(
TO_DATE('20181103','YYYYMMDD') ,'DD-MON-YY') AS DATE_TEST
FROM DUAL
)
Here, TO_DATE('20181103','YYYYMMDD') ,'DD-MON-YY' - will convert 20181103 as 03-NOV-2018.
So the result from the WITH clause (Which is 03-NOV-2018) will be used in another query :
SELECT next_day (TO_DATE(DATE_TEST,'DD-MON-YY')-7,'FRIDAY') Last_Friday
FROM TEMP1;
Here DATE_TEST is output from with clause. First
TO_DATE(DATE_TEST,'DD-MON-YY')-7
It is taking previous 7 days from the mentioned date (which is currently DATE_TEST : 03-NOV -2018) So It will take all the last 7 days from 03-NOV-2018.
Assuming :
DATE DAY Order
28-10-2018 SUN 1
29-10-2018 MON 2
30-10-2018 TUE 3
31-10-2018 WED 4
01-11-2018 THURS 5
02-11-2018 FRI 6
03-11-2018 SAT 7
We got all 7 days mentioned above.
next_day (TO_DATE(DATE_TEST,'DD-MON-YY')-7,'FRIDAY')
Now from next_day, we can get another day and here, we are asking for FRIDAY by mentioning it in the argument. So FRIDAY is 02-11-2018.
So the output will be 02-11-2018.
This may solve your query
select day, to_char(to_date(day,'YYYYMMDD'),'DY') f1,
case to_char(to_date(day,'YYYYMMDD'),'DY')
when 'FRI' then 0
when 'SAT' then -1
when 'SUN' then -2
when 'MON' then -3
when 'TUE' then 3
when 'WED' then 2
when 'THU' then 1
end as f2,
to_char(to_date(day,'YYYYMMDD')+ case to_char(to_date(day,'YYYYMMDD'),'DY')
when 'FRI' then 0
when 'SAT' then -1
when 'SUN' then -2
when 'MON' then -3
when 'TUE' then 3
when 'WED' then 2
when 'THU' then 1
end,'YYYYMMDD') as f3
from test_cal;
DAY F1 F2 F3
-------- --------- ---------- --------
20181026 FRI 0 20181026
20181027 SAT -1 20181026
20181028 SUN -2 20181026
20181029 MON -3 20181026
20181030 TUE 3 20181102
20181031 WED 2 20181102
20181101 THU 1 20181102
20181102 FRI 0 20181102
20181103 SAT -1 20181102
9 rows selected.