To count the number of weeks between two dates in oracle - oracle

I have used the below query to find the number of weeks between two dates:
select count(week_id)
from fw
where week_begin_date >= '2015-01-01'
and week_end_date <= '2015-12-31';
Expected result should be 53 but the actual result is 51.
Kindly help on this.

Can't you just use the week of year function? subtract if needed...
select to_char(to_date('12/31/2015','MM/DD/YYYY'),'WW') from dual;
select To_Number(to_char(to_date('12/31/2015','MM/DD/YYYY'),'WW')) -
To_number(to_char(to_date('01/01/2015','MM/DD/YYYY'),'WW')) +1
from dual;
We have to add +1 because weeks start at 1 not 0.
Now maybe you're after the ISO week format which would be IW instead of WW.
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.
IW: Week of year (1-52 or 1-53) based on the ISO standard.

I know this is a very old thread, but I used a modified version of this code today that I thought might be beneficial for someone else. My modification solves for the fractional week issue and the removal of the minus sign:
SELECT
CEIL(
ABS(
(
TO_DATE('20160101','YYYYMMDD')
- TO_DATE('20161231','YYYYMMDD')
) / 7
)
) AS DT
FROM DUAL
The ABS function takes the absolute value of the result of subtracting the two dates, thereby eliminating the minus sign if it exists (I switched the order of the dates to demonstrate this). The CEIL function rounds up any fractional week to the next whole week (I changed the year to 2016 to demonstrate this - CEIL is logically equivalent to the ROUNDUP function in Excel). NOTE: We have to apply the ABS function first (inner parenthesis) because CEIL will also round up negative numbers, which would in effect round the weeks down if ABS were applied after CEIL. The result of this calculation is 53 (subtraction of the dates returns about -52.142857, ABS removes the minus sign, CEIL rounds up to 53).
I hope this ends up being useful to someone. Thanks.

Did you try this:
SELECT
REPLACE((
to_date('20151231','yyyymmdd') - to_date('20150101','yyyymmdd')
)/7, '-', '')
FROM
DUAL

Related

floor while calculating between two dates is giving 0 in Oracle

I have two dates by which I am calculating no of years/months. For below 2 dates I am getting output as 0 as it should return 0.4 months.
Here is my query
select floor((months_between(to_date('2022-07-01T00:00:00+05:30'), to_date('2022-01-11T00:00:00+05:30', 'dd-mm-yy'))) /12)
from dual;
Please suggest what I am doing wrong here
The floor function:
returns the largest integer equal to or less than n
so there is no way it can return 0.4. The ceil function is the similar. Neither takes an argument allowing retention of decimal places. And you don't want to round it, as in your example that would give 0.5, not 0.4.
Fortunately you can use trunc, which does have a decimal-place argument:
The TRUNC (number) function returns n1 truncated to n2 decimal places.
So you want trunc(<difference between dates>, 1) to get retain 1 decimal place.
select trunc (
months_between(
CAST(TO_TIMESTAMP_TZ('2022-07-01T00:00:00+05:30','YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS DATE),
CAST(TO_TIMESTAMP_TZ('2022-01-11T00:00:00+05:30','YYYY-MM-DD"T"HH24:MI:SSTZH:TZM') AS DATE)
) / 12
, 1
) as result
from dual;
.4
Here trunc behaves essentially as you would want floor(n1, n2) to if that existed; there is no equivalent for ceil, but you can work around that. The same method can be applied here too, but isn't needed; I've included it in this db<>fiddle for fun.
You want:
to use TO_TIMESTAMP_TZ and not TO_DATE
to use a format model that matches the timestamp format such as YYYY-MM-DD"T"HH24:MI:SSTZD
to use FLOOR before dividing by 12 if you want to find the number of full months.
select FLOOR(
MONTHS_BETWEEN(
to_timestamp_tz('2022-07-01T00:00:00+05:30', 'YYYY-MM-DD"T"HH24:MI:SSTZD'),
to_timestamp_tz('2022-01-11T00:00:00+05:30', 'YYYY-MM-DD"T"HH24:MI:SSTZD')
)
) / 12 AS full_months_diff
from dual;
Which outputs:
FULL_MONTHS_DIFF
.4166666666666666666666666666666666666667
Alternatively, you could use the difference between the timestamps as an INTERVAL YEAR TO MONTH data type:
select EXTRACT(
YEAR FROM
( to_timestamp_tz('2022-07-01T00:00:00+05:30', 'YYYY-MM-DD"T"HH24:MI:SSTZD')
- to_timestamp_tz('2022-01-11T00:00:00+05:30', 'YYYY-MM-DD"T"HH24:MI:SSTZD')
) YEAR TO MONTH
) AS years,
EXTRACT(
MONTH FROM
(to_timestamp_tz('2022-07-01T00:00:00+05:30', 'YYYY-MM-DD"T"HH24:MI:SSTZD')
- to_timestamp_tz('2022-01-11T00:00:00+05:30', 'YYYY-MM-DD"T"HH24:MI:SSTZD')
) YEAR TO MONTH
) AS months
from dual;
YEARS
MONTHS
0
6
Which rounds up the number of months.
db<>fiddle here

Is there a functon similar to DateDiff in MonetDB which can calculate number of weeks between two dates

Consider two dates, "01-Jan-2011' & '01-Oct-2011'.
I wish to calculate number of weeks in between these dates.
I have tried the following:
select extract ( week from ( (current_date+ interval '5' day) - current_date ));
It returns error " no such unary operator 'week(day_interval)'"
I am able to find number of days by using following :
select extract ( day from ( (current_date+ interval '5' day) - current_date ));
the line above returns the output
Is there any way I can achieve the same?
Further, MonetDB considers week from Monday to Sunday(1-7). Is there any way this can be updated/ customised to Sunday to Saturday.
Thanks.
There are a couple of possibilities that I can think of:
select date '2011-10-01' - date '2011-01-01';
results in a INTERVAL DAY value, actually expressed in seconds of the difference, i.e. 23587200.000. This you could divide by (72460*60), i.e. the number of seconds in a week. But it's still an INTERVAL type, not an INTEGER.
Another way is to first convert the date to integers: the number of seconds since "the epoch" (Jan 1, 1970):
select epoch_ms(date '2011-10-01');
This actually give milliseconds since the epoch, so an extra factor of 1000.
This result you can then manipulate to get what you want:
select (epoch_ms(date '2021-02-02') - epoch_ms(date '2020-12-31')) / (7*24*60*60*1000);
This results in a HUGEINT value (if you have 128 bit integers in your system, i.e. anything compiled with GCC or CLANG), so you can convert this to INTEGER:
select cast((epoch_ms(date '2011-10-01') - epoch_ms(date '2011-01-01')) / (7*24*60*60*1000) as integer);

Oracle - How to get date from YEAR, WEEKNUM and WEEKDAY?

I need to find the date of particular year, week, and weekday in oracle.
Is there a built-in function for this in oracle? or how can I achieve this?
Ex: If Year=2019, Week=22, Day=2(Tuesday), Then date should be '28-05-2019'.
Assuming "Week" and "Year" means week and year according to ISO-8601 you can use this function:
CREATE OR REPLACE FUNCTION ISOWeekDate(YEAR INTEGER, WEEK INTEGER, DAY INTEGER) RETURN DATE DETERMINISTIC IS
res DATE;
BEGIN
IF WEEK > 53 OR WEEK < 1 THEN
RAISE VALUE_ERROR;
END IF;
res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - INTERVAL '7' DAY, 'MONDAY') + ( WEEK - 1 ) * 7;
IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
RETURN res + DAY - 1;
ELSE
RAISE VALUE_ERROR;
END IF;
END ISOWeekDate;
I think there is no built-in function for this, you will have to build one on your own.
below is one of the solutions you can make use of.
WITH FUNCTION getDate(p_year IN NUMBER, p_weeks IN NUMBER, p_day in NUMBER) RETURN DATE
IS
v_tmp date;
v_day number;
BEGIN
v_tmp := to_date('01/01/'||to_char(p_year),'dd/mm/yyyy');
v_day := to_char(v_tmp,'D');
RETURN v_tmp+(p_weeks-1)*7+p_day-(v_day)+1;
END;
SELECT getDate(2019,22,2)
FROM DUAL;
/
As per my NLS_TERRITORY settings, Oracle numbers the day of the week starting from Sunday, but from your example, you seem to be considering Monday as day 1 of the week. So, the same adjustment is made to the function to return the expected result.
Also, please note that with clause function is a new feature of Oracle 12c, if you happen to use an older version of Oracle, you will have to create the stored function before calling it.
Logically, the ISO week number is the occurrence of Thursdays in that (Gregorian) calendar year. The ISO year of an ISO week, is the Gregorian year in which the Thursday of that ISO week falls.
In the ISO schema, weeks always contain 7 days. Weeks start on a Monday, finish on a Sunday, and the days of that week are numbered 1-7.
This weekday numbering scheme often differs from that returned from built-in WEEKDAY functions and similar in different software packages (or requires particular database settings), which is something to be aware of. You will need available a function that returns the weekday of a particular date according to the ISO numbering scheme.
The first Thursday of the year can occur anywhere in the range 01-Jan to 07-Jan.
If the first Thursday falls on 01-Jan, then the first ISO week of that year will include days (29/31-Dec) from the previous Gregorian year.
If the first Thursday falls on 07-Jan, then the last ISO week of the previous Gregorian year will include days (01/03-Jan) from the current Gregorian year.
If the first Thursday falls on 04-Jan, then by implication the first ISO week of the year runs from Monday 01-Jan.
To devise an algorithm, the easiest approach is probably to establish on what weekday the 04-Jan falls in the given year, then apply the following calculation 4 - weekday. If the weekday of 04-Jan is found to be Thursday, the result will be 0. If it is Monday, the result will be 3 (4-1). If it is Sunday, the result will be -3 (4-7). We will store this offset for use after the next step.
We can derive a provisional day-of-year-offset from the ISO week and day numbers as follows: (((iso_week - 1) * 7) - (4 - iso_day)).
We then apply the offset derived in the first stage for the final day-of-year-offset. This is an offset from 04-Jan of the given Gregorian year. This offset may be a minus figure, if the relevant day falls prior to 04-Jan of the given year.
Given that day-of-year-offset, we can then use built-in functions to produce 04-Jan of the given year, and apply the day-of-year-offset to produce the final Gregorian date.
For example, given 2019-W01-1.
2019-01-04 is a Friday, so it's weekday is 5. The result of the first step is -1 (4-5). The result of the second step is -3 (((1-1)*7) - (4-1)). Added together they produce a day-of-year-offset of -4. 04-Jan-2019 offset by -4 results in 31-Dec-2018.
And that is our result: 2019-W01-1 = 2018-12-31.

ORA-01873: the leading precision of the interval is too small

When I try to query differences between 2 timestamps in Oracle, the result returns the interval normally.
select NVL2(ERROR_OUT_TS, ERROR_OUT_TS-ERROR_IN_TS, null) from table
or
select interval '8 00:00:10' day to second from dual
But when I try to select rows with greater than some interval, Oracle give me this error.
where ERROR_OUT_TS - ERROR_IN_TS <= '00 00:02:00'
or
where ERROR_OUT_TS - ERROR_IN_TS >= interval '0 00:00:10' day to second
It keeps saying that "the leading precision is too small".
I am trying to return the interval like 0 00:00:00:000
It is working fine for other customers. Only few customers are experiencing it.
How to choose the correct precision?
Try:
select interval '8 00:00:10' day(4) to second(4) from dual;
What it does is that 'day' and 'second' are default 2 digits, this expands them to accept 4. You probably just need 3 though.

Adding one month to saved date(oracle)

I have a table A which contains a Date type attribute. I want to write a query to select the date in another table B with value one month after the value in A.Any one know how to do it in oracle?
uhm... This was the first hit on google:
http://psoug.org/reference/date_func.html
It seems you're looking for the "add_months" function.
You need to use the ADD_MONTHS function in Oracle.
http://www.techonthenet.com/oracle/functions/add_months.php
Additional info: If you want to use this function with today's date you can use ADD_MONTHS(SYSDATE, 1) to get one month from now.
The question is to select a date_field from table b where date_field of table b is one month ahead of a date_field in table a.
An additional requirement must be taken into consideration which is currently unspecified in the question. Are we interested in whole months (days of month not taken into consideration) or do we want to include the days which might disqualify dates that are one month ahead but only by a couple of days (example: a=2011-04-30 and b=2011-05-01, b is 1 month ahead but only by 1 day).
In the first case, we must truncate both dates to their year and month values:
SELECT TRUNC( TO_DATE('2011-04-22','yyyy-mm-dd'), 'mm') as trunc_date
FROM dual;
gives:
trunc_date
----------
2011-04-01
In the second case we don't have to modify the dates.
At least two approaches can be used to solve the initial problem:
First one revolves around adding one month to the date_field in table a and finding a row in table b with a matching date.
SELECT b.date_field
FROM tab_a as a
,tab_b as b
WHERE ADD_MONTHS( TRUNC( a.date_field, 'mm' ), 1) = TRUNC( b.date_field, 'mm' )
;
Note the truncated dates. Leaving this out will require a perfect day to day match between dates.
The second approaches is based on calculating the difference in months between two dates and picking a calculation that gives a 1 month difference.
SELECT b.date_field
FROM tab_a as a
,tab_b as b
WHERE months_between( TRUNC( b.date_field, 'mm') , TRUNC(a.date_field, 'mm') ) = 1
The order of the fields in months_between is important here. In the provided example:
for b.date_field one month ahead of a.date_field the value is 1
for b.date_field one month before a.date_field the value is -1 (negative one)
Reversing the order will also reverse the results.
Hope this answers your question.

Resources