I want to get all dates of a month based on day name like if I want to get all FRIDAY dates from current date to a specific end date. I got a solution in SQL but can't find any solution in ORACLE.
You can use hierarchy query with next_day function as follows:
-- input variable
with dataa (start_date, end_date) as
(select date '2020-11-01', date '2020-12-15' from dual)
-- your query starts from here
select next_day((level-1)*7 + (start_date - 1), 'FRIDAY')
FROM DATAA
connect by
next_day((level-1)*7 + (start_date - 1),'FRIDAY') <= end_date
Db<>fiddle here
You can use hierarchical query as
WITH t AS
(
SELECT TRUNC(sysdate,'MM')+level-1 AS Fridays
FROM dual
WHERE TO_CHAR(TRUNC(sysdate,'MM')+level-1,'Dy','NLS_DATE_LANGUAGE=American')='Fri'
CONNECT BY level <= LAST_DAY(TRUNC(sysdate)) - TRUNC(sysdate,'MM') + 1
)
SELECT *
FROM t
WHERE Fridays BETWEEN :data1 AND :date2
Demo
Using connect by then filtering by Friday is a simple solution. In the example below I am using July 1st as the start date and December 1st as the end date.
SELECT DATE '2020-7-1' + LEVEL AS friday_dates
FROM DUAL
WHERE TO_CHAR (DATE '2020-7-1' + LEVEL, 'DY') = 'FRI'
CONNECT BY LEVEL <= DATE '2020-12-1' - DATE '2020-7-1';
Related
I try to get a query without parameters to obtain the list of dates from the current month.
Something like this:
SYSDATE = 16/07/15
I want the next list:
01/07/15
02/07/15
...
30/07/15
31/07/15
Here's what I got to work:
SELECT TRUNC(SYSDATE, 'MM') + LEVEL - 1 AS day
FROM dual
CONNECT BY TRUNC(TRUNC(SYSDATE, 'MM') + LEVEL - 1, 'MM') = TRUNC(SYSDATE, 'MM')
;
The key in this query is TRUNC(SYSDATE, 'MONTH') which is the first day of the current month.
We use hierarchical queries to keep adding one day to the first day of the month until the value is no longer in the current month.
We use LEVEL - 1 because LEVEL starts from 1 and we need it to start from zero.
Here's a pseudo-query for what the above query does:
SELECT (start_of_month + days) AS day
FROM dual
WHILE MONTH_OF(start_of_month + days) = current_month
This query be a bit easier to understand:
SELECT *
FROM
(
SELECT TRUNC(SYSDATE, 'MM') + LEVEL - 1 AS day
FROM dual
CONNECT BY LEVEL <= 32
)
WHERE EXTRACT(MONTH FROM day) = EXTRACT(MONTH FROM SYSDATE)
Selects all the days for current month
SELECT TO_CHAR (TRUNC (SYSDATE, 'MM'), 'YYYYMMDD')+(LEVEL - 1) each_date
FROM DUAL a
CONNECT BY LEVEL < (TO_NUMBER (TO_CHAR (TRUNC (SYSDATE, 'MM') - 1, 'DD'))+1)
This should work:
select trunc(sysdate, 'MONTH') + rownum - 1
from dual
connect by rownum <= to_number(to_char(last_day(sysdate), 'DD'));
This is a trick using connect by. I truncate the date at the month level, effectively setting it to the 1st day of the month, add a day for each "level" and then filter for any day that occurs outside the month.
select day_of_month
from
(select (level - 1) + trunc(to_date('07/16/2015','MM/DD/YYYY'),'MM') day_of_month
from
dual
connect by level <= 31)
where day_of_month < add_months(trunc(to_date('07/16/2015','MM/DD/YYYY'),'MM'),1);
Please help to derive first day of a given week_no in oracle not from given date.
You can try following query:-
SELECT NEXT_DAY(MAX(d), 'SUN') REQUESTED_SUN
FROM (SELECT TO_DATE('01-01-2015', 'DD-MM-YYYY') + (ROWNUM-1) d FROM DUAL CONNECT BY LEVEL <= 366)
WHERE TO_CHAR(d, 'WW') = Your_Desired_WEEK_NO-1;
This might be helpful to you.
Use this query
Select TRUNC (Trunc(sysdate,'yyyy')+(:num-1)*7,'IW') from duaL;
:num is number of week from year 2015, or put year what you need instead of sysdate.
You can use this function to get the date of the ISO week:
CREATE FUNCTION TO_ISO_WEEK_DATE(
week NUMBER,
year NUMBER
) RETURN DATE DETERMINISTIC
IS
BEGIN
RETURN NEXT_DAY(
TO_DATE( TO_CHAR( year, '0000' ) || '0104', 'YYYYMMDD' )
- INTERVAL '7' DAY, 'MONDAY'
)
+ ( week - 1 ) * 7;
END TO_ISO_WEEK_DATE;
/
I have dates stored like String in database.
The format is 'yyyy-ww' (example: '2015-43').
I need to get the first day of the week.
I tried to convert this string into date but there is no 'ww' option for the function "to_date".
Do you have an idea to perform this convertion?
EDIT
Test results based on the answers -
Thanks for your anwsers, but I have many problems to apply your solutions to my context:
select
TRUNC ( 2015 + ((43 - 1) * 7), 'IW' )
from dual
==> Error : ORA-01722: invalid number
select
TRUNC(to_date('2015','YYYY')+ to_number('01') *7, 'IW')
from dual
==> 2015-02-02 00:00:00
I waited for a date in january
select
trunc(to_date(regexp_substr('2015-01', '\d+',1,2), 'YYYY') + regexp_substr('2015-01', '\d+') * 7, 'IW') dt2
from dual
==> 0039-09-14 00:00:00
select
regexp_substr('2015-01', '\d+',1,2) as res1,
regexp_substr('2015-01', '\d+') * 7 as res2
from dual
==> res1 = 01
==> res2 = 14105
try to use by truncate
with t as (
select '16-2010' dt from dual
)
--
--
select dt,
trunc(to_date(regexp_substr(dt, '\d+',1,2), 'YYYY') + regexp_substr(dt, '\d+') * 7, 'IW') dt2
from t
I have dates stored like String in database.
You should never do that. It is a bad design. you should store date as DATE and not as a string. For all kinds of requirements for date manipulations Oracle provides the required DATE functions and format models. As and when needed, you could extract/display the way you want.
I need to get the first day of the week.
TRUNC (dt, 'IW') returns the Monday on or before the given date.
Anyway, in your case, you have the literal as YYYY-WW format. You could first extract the year and week number and combine them together to get the date using TRUNC.
TRUNC ( year + ((week_number - 1) * 7)
, 'IW
)
So, the above should give you the Monday of the week number passed for that year.
SQL> WITH DATA AS
2 ( SELECT '2015-43' str FROM dual
3 )
4 SELECT TRUNC(to_date(SUBSTR(str, 1, 4),'YYYY')+ to_number(SUBSTR(str, instr(str, '-',1)+1))*7, 'IW')
5 FROM DATA
6 /
TRUNC(TO_
---------
23-NOV-15
SQL>
Similar to Lalit's, however, I think I've corrected the math (his seemed to be off a bit when I tested .. )
with w_data as (
select sysdate + level +200 d from dual connect by level <= 10
),
w_weeks as (
select d, to_char(d,'yyyy-iw') c
from w_data
)
SELECT d, c, trunc(d,'iw'),
TRUNC(
to_date(SUBSTR(c, 1, 4)||'0101','yyyymmdd')-8+to_char(to_date(SUBSTR(c, 1, 4)||'0101','yyyymmdd'),'d')
+to_number(SUBSTR(c, instr(c, '-',1)+1)-1)*7 ,'IW')
FROM w_weeks;
The extra columns help show the dates before, and after.
I would do the following:
WITH d1 AS (
SELECT '2015-43' AS mydate FROM dual
)
SELECT TRUNC(TRUNC(TO_DATE(REGEXP_SUBSTR(mydate, '^\d{4}'), 'YYYY'), 'YEAR') + (COALESCE(TO_NUMBER(REGEXP_SUBSTR(mydate, '\d+$')), 0)-1) * 7, 'IW')
FROM d1
The first thing the above query does is get the first four digits of the string 2015-43 and truncates that to the closest year (if you convert convert 2015 using TO_DATE() it returns a date within the current month; that is SELECT TO_DATE('2015', 'YYYY') FROM dual returns 01-FEB-2015; we need to truncate this value to the YEAR in order to get 01-JAN-2015). I then add the number of weeks minus one times seven and truncate the whole thing by IW. This returns a date of 01-OCT-2015 (see SQL Fiddle here).
According ISO the 4th of January is always in week 1, so your query should look like
Select
TRUNC(TO_DATE(REGEXP_SUBSTR(your_column, '^\d{4}')||'-01-04', 'YYYY-MM-DD')
+ 7*(REGEXP_SUBSTR(your_column, '\d$')-1), 'IW')
from your_table;
However, there is a problem. ISO year used for Week number can be different than actual year. For example, 1st Jan 2008 was in ISO week number 53 of 2007.
I think a proper working solution you get only when you generate ISO weeks from date value.
WITH w AS
(SELECT TO_CHAR(DATE '2010-01-04' + LEVEL * INTERVAL '7' DAY, 'IYYY-IW') AS week_number,
TRUNC(DATE '2010-01-04' + LEVEL * INTERVAL '7' DAY, 'IW') AS first_day
FROM dual
CONNECT BY DATE '2010-01-04' + LEVEL * INTERVAL '7' DAY < SYSDATE)
SELECT your_Column, first_day
FROM w your_table
JOIN w ON week_number = your_Column;
Your date range must bigger than 2010-01-04 and not bigger than current day.
This is what I used:
select
to_date(substr('2017/01',1,4)||'/'||to_char(to_number(substr('2017/01',6,2)*7)-5),'yyyy/ddd') from dual;
Does anyone know how can I calculate the number of weekdays between two date fields? I'm using oracle sql developer. I need to find the average of weekdays between multiple start and end dates. So I need to get the count of days for each record so I can average them out. Is this something that can be done as one line in the SELECT part of my query?
This answer is similar to Nicholas's, which isn't a surprise because you need a subquery with a CONNECT BY to spin out a list of dates. The dates can then be counted while checking for the day of the week. The difference here is that it shows how to get the weekday count value on each line of the results:
SELECT
FromDate,
ThruDate,
(SELECT COUNT(*)
FROM DUAL
WHERE TO_CHAR(FromDate + LEVEL - 1, 'DY') NOT IN ('SAT', 'SUN')
CONNECT BY LEVEL <= ThruDate - FromDate + 1
) AS Weekday_Count
FROM myTable
The count is inclusive, meaning it includes FromDate and ThruDate. This query assumes that your dates don't have a time component; if they do you'll need to TRUNC the date columns in the subquery.
You could do it the following way :
Lets say we want to know how many weekdays between start_date='01.08.2013' and end_date='04.08.2013' In this example start_date and end_date are string literals. If your start_date and end_date are of date datatype, the TO_DATE() function won't be needed:
select count(*) as num_of_weekdays
from ( select level as dnum
from dual
connect by (to_date(end_date, 'dd.mm.yyyy') -
to_date(start_date, 'dd.mm.yyyy') + 1) - level >= 0) s
where to_char(sysdate + dnum, 'DY',
'NLS_DATE_LANGUAGE=AMERICAN') not in ('SUN', 'SAT')
Result:
num_of_weekdays
--------------
2
Checkout my complete working function code and explanation at
https://sqljana.wordpress.com/2017/03/16/oracle-calculating-business-days-between-two-dates-in-oracle/
Once you have created the function just use the function as part of the SELECT statement and pass in the two date columns for Start and End dates like this:
SELECT Begin_Date, End_Date, fn_GetBusinessDaysInterval(Begin_Date, End_Date) AS BusinessDays FROM YOURTABLE;
to_char(sysdate,'Day') returns the current day of the week. What I want is to get the date of the most recent "sunday" that passed. Of course we can go for a complex query to get it done. But is there any simple way I'm not aware of?
You can do it with
SELECT NEXT_DAY(SYSDATE-8, 'SUN') FROM DUAL;
here
SYSDATE-8
returns the day before 8 days &
NEXT_DAY(mydate, 'SUN')
returns the next sunday to it
You can do it with a query as simple as this:
SELECT dt
FROM ( SELECT SYSDATE - LEVEL - 1 dt
FROM DUAL
CONNECT BY LEVEL < 8)
WHERE TO_CHAR ( dt, 'd' ) = 1
I think NEXT_DAY(SYSDATE-6, 'SUN') would work. Assuming current day as sunday, I go back 6 days (i.e. last monday) and so when I look for the next sunday, I'd get the sysdate itself. Whereas, next_day(sysdate-8,'SUN') could be used to get the last day of previous week. Thanks for your efforts.
SELECT dt
FROM ( SELECT to_date('5/23/2014') - LEVEL + 1 dt
FROM DUAL
CONNECT BY LEVEL < 8)
WHERE TO_CHAR ( dt, 'd' ) = 1
I changed LEVEL - 1 dt to LEVEL + 1 dt to get it to work to find the previous Sunday.