SQL oracle where date field = Last Friday - sql

I have a where clause with a date field, I want it to find the latest Friday when this auto runs every Monday or Tuesday of the following week.
Currently:
WHERE b.CALENDAR_DATE = To_Date('2020-08-30', 'YYYY-MM-DD')
I want to find the latest Friday

You can use TRUNC( date_value, 'IW' ) (which is language independent) to truncate to the start of the ISO week, which is always a Monday, and then subtract 3 days. You will also want to add 2 days before truncating so that the filter is correct if SYSDATE is a Saturday or Sunday.
WHERE b.CALENDAR_DATE >= TRUNC( SYSDATE + INTERVAL '2' DAY, 'IW' ) - INTERVAL '3' DAY
AND b.CALENDAR_DATE < TRUNC( SYSDATE + INTERVAL '2' DAY, 'IW' ) - INTERVAL '2' DAY
(Note: dates can have a non-zero time component so if you want all dates on the last Friday then you will need a range of values rather than just comparing to last Friday at midnight.)
Or you can use NEXT_DAY( date_value - INTERVAL '8' DAY, 'FRIDAY' ) (which is language dependent):
WHERE b.CALENDAR_DATE >= NEXT_DAY( TRUNC( SYSDATE ) - INTERVAL '8' DAY, 'FRIDAY' )
AND b.CALENDAR_DATE < NEXT_DAY( TRUNC( SYSDATE ) - INTERVAL '8' DAY, 'FRIDAY' ) + INTERVAL '1' DAY
db<>fiddle here

Related

Is there a way to use SYSDATE with a weekly date?

So I've been trying to fetch some daily data with SYSDATE on a date type YYYYMMDD as following:
SELECT dates, trunc(calendar_date, 'DD') calendar_dates, weekday_nbr
FROM db.date
WHERE dates BETWEEN to_char(TRUNC(SYSDATE)-2, 'YYYYMMDD') AND to_char(TRUNC(SYSDATE)-1, 'YYYYMMDD')
But now I'm trying to use the same but on a YYYY+MM+Week date type with not much success
I tried using:
SELECT T time, period, fiscal_week
FROM db.time
WHERE time BETWEEN to_char(TRUNC(SYSDATE)-2, 'W') AND to_char(TRUNC(SYSDATE)-1,'W')
With time as a 7 digit number, and period and fiscal week as a 2 digit number
Knowing that there's no way I can truncate such date type, how can TRUNC SYSDATE YYYY+MM+Week to get the data on the last 2 weeks?
Also I was thinking about maybe getting the totals from a set day and then dropping all but the last 2 weeks, but on the long run maybe that would be time consuming.
Knowing that there's no way I can truncate such date type, how can TRUNC SYSDATE YYYY+MM+Week to get the data on the last 2 weeks?
Assuming that your fiscal weeks are from Monday-Sunday then you can truncate to the start of the ISO week (which is always Midnight on Monday) and use that for the basis of the comparison:
SELECT *
FROM db.time
WHERE dates >= TRUNC(SYSDATE, 'IW') - INTERVAL '14' DAY
AND dates < TRUNC(SYSDATE, 'IW')
If you have a column that is for weeks then you should still use a DATE data type and add a CHECK constraint (and can use virtual columns to generate the week and the year):
CREATE TABLE time (
dt DATE
CHECK (dt = TRUNC(dt, 'IW')),
year NUMBER(4,0)
GENERATED ALWAYS AS (EXTRACT(YEAR FROM dt)),
month NUMBER(2,0)
GENERATED ALWAYS AS (EXTRACT(MONTH FROM dt)),
week NUMBER(1,0)
GENERATED ALWAYS AS (FLOOR((dt - TRUNC(dt, 'MM'))/7) + 1),
time VARCHAR2(7)
GENERATED ALWAYS AS (
CAST(
TO_CHAR(dt, 'YYYYMM')
|| (FLOOR((dt - TRUNC(dt, 'MM'))/7) + 1)
AS VARCHAR2(7)
)
)
-- ...
);
fiddle
Then you can use the logic above on the date column.
If you do not have a DATE column then you will need to convert your YYYYMMW number into a DATE and then use the logic above.
For example, if the logic for your fiscal weeks (which you have not described) is that the first week of each month starts on the first Monday of the month then you can convert the YYYYMMW number to a DATE using:
SELECT NEXT_DAY(
TO_DATE(SUBSTR(time, 1, 6), 'YYYYMM') - INTERVAL '1' DAY,
'MONDAY'
) + INTERVAL '7' DAY * (SUBSTR(time, 7, 1) - 1) AS week_start
FROM db.time
and then could use it to filter the table using:
SELECT *
FROM (
SELECT t.*,
NEXT_DAY(
TO_DATE(SUBSTR(time, 1, 6), 'YYYYMM') - INTERVAL '1' DAY,
'MONDAY'
) + INTERVAL '7' DAY * (SUBSTR(time, 7, 1) - 1) AS week_start
FROM db.time t
)
WHERE week_start >= TRUNC(SYSDATE, 'IW') - INTERVAL '14' DAY
AND week_start < TRUNC(SYSDATE, 'IW')
If you have different logic for calculating when fiscal weeks start then you will need to apply that logic to the conversion.

previous friday of month

I am trying to write a query that will return the last friday of the previous month This is what I have so far.
SELECT sysdate
FROM DUAL
where (LAST_DAY( SYSDATE ) - INTERVAL '7' DAY,
'Friday' );
Consider:
select next_day(trunc(sysdate, 'month') - interval '8' day, 'Friday') from dual
Rationale:
trunc(sysdate, 'month') gives you the first day of the current month
we offset that value by 8 days so we can the the date 7 days before the end of the previous month
then, next_day() returns the next Friday after this date, that is the last Friday of the month
Try this:
SELECT NEXT_DAY( LAST_DAY( TO_DATE('01-' || TO_CHAR(SYSDATE, 'MON-YYYY')) - 1 ) - INTERVAL '7' DAY, 'FRIDAY' ) FROM DUAL;

last day/time of month

How do I get the last day of the month to be 11:59:59 pm? Right now it is showing 05/31/2019 12:00 AM. If I just do sysdate it just shows the time I ran it. Thanks.
LAST_DAY(TRUNC(SYSDATE,'MM'))
Try adding one day to the last day of the current month, then subtracting one minute:
SELECT
LAST_DAY(TRUNC(SYSDATE,'MM')) + INTERVAL '1' DAY - INTERVAL '1' SECOND
FROM dual;
Or, if you want to also see the time component, use CURRENT_TIMESTAMP in place of SYSDATE:
SELECT
LAST_DAY(TRUNC(CURRENT_TIMESTAMP,'MM')) + INTERVAL '1' DAY - INTERVAL '1' SECOND
FROM dual;
This outputted:
30.06.2019 23:59:59
The oldfashioned way would be to subtract a second (that's what 1 / (24*60*60) represents as there are 24 hours in a day, 60 minutes in an hour and 60 seconds in a minute) from the first day of the next month (and that's what trunc(add_months(sysdate, 1)) does):
SQL> select sysdate today,
2 trunc(add_months(sysdate, 1)) - 1/(24*60*60) result
3 from dual;
TODAY RESULT
---------------------- ----------------------
06/01/2019 07:52:40 AM 06/30/2019 11:59:59 PM
SQL>
I would use:
SELECT TRUNC(SYSDATE, 'MM') + INTERVAL '1' MONTH - INTERVAL '1' SECOND
FROM dual;
(This has one less step than Tim's solution.)
Or in the older-fashioned method:
SELECT ADD_MONTHS(TRUNC(SYSDATE, 'MM'), 1) - 1/(24*60*60)
If you convert this to a timestamp, you will see the time value:
SELECT CAST(TRUNC(sysdate, 'MM') + INTERVAL '1' MONTH - INTERVAL '1' SECOND as TIMESTAMP)
FROM dual;

get previous week date in select query

I have below query which i am using for reporting in Cognos. I am doing reporting every week on Monday for the previous week from Monday till Sunday.
Currently this date is hardcoded but i want to make it dynamic so that everytime when i run this report on Monday i dont have to change the date for previous week.
Is it possible i can make DAY_DATE dynamic using something like sysdate in select query ?
select ID,NAME,DAY_DATE
from TEST_REPORT
WHERE DAY_DATE BETWEEN to_date ('20170904', 'YYYYMMDD') and to_date ('20170910', 'YYYYMMDD');
You can calculate start and end dates of previous week from the current date using TRUNC (date) function.
Let say you are running the query on monday 2017-09-11, then on friday 2017-09-15, and the query must always generate a report for previous week.
This query calculates a start date of the current week:
SELECT trunc( date '2017-09-11', 'IW' ) as x,
trunc( date '2017-09-15', 'IW' ) as y
from dual;
X Y
---------------- ----------------
2017/09/11 00:00 2017/09/11 00:00
To calculate a start date of the previous week, substract 1 day from the above dates, and use TRUCT again:
SELECT trunc( trunc( date '2017-09-11', 'IW' ) - 1, 'IW') as start_last_week,
trunc( trunc( date '2017-09-15', 'IW' ) - 1, 'IW') as start_last_week1
from dual;
START_LAST_WEEK START_LAST_WEEK1
---------------- ----------------
2017/09/04 00:00 2017/09/04 00:00
So, in your query just use this clause (date >= than a start of previous week and < that a start of current week):
WHERE DAY_DATE>= trunc( trunc( sysdate, 'IW' ) - 1, 'IW')
and DAY_DATE < trunc( sysdate, 'IW' )

How to determine week of a quarter in Oracle query

I want to find the Week of a Quarter from a sql date in Oracle.
I tried below query to find the year, quarter and week.
But the week field gives the 'Week of the month' not the 'Week of the quarter'
select to_char(sysdate, 'YYYY')|| '-Q' || to_char(sysdate, 'Q') || '-W' || >to_char(sysdate, 'w') as "Current Time"
from dual;
Above query returns '2016-Q2-W3' as the date falls in the 3rd week of the month.
Say sysdate is '17th June, 2016'
I am expecting result as
2016-Q2-W12
My Week range is (Sunday - Saturday)
Since the '17th June, 2016' comes under 12th week of the quarter, it should be W12.
Thanks in advance.
This will get the week (Sunday - Saturday) of the quarter:
SELECT TO_CHAR( SYSDATE, 'YYYY-"Q"Q-"W"' )
|| ( 7 + TRUNC( SYSDATE + 1, 'IW' ) - TRUNC( TRUNC( SYSDATE, 'Q' ) + 1, 'IW' ) ) / 7;
AS "Current Time"
FROM DUAL
Explanation:
You can find the Sunday which was either on-or-just-before a given date using NEXT_DAY( TRUNC( date_value ), 'SUNDAY' ) - 7 (which is dependant on the NLS_TERRITORY setting) or TRUNC( date_value + 1, 'IW' ) - 1 (which is shorter and not dependant on any settings).
TRUNC( date_value, 'Q' ) gives the date of the first day of the quarter containing the value date (i.e. either 1st January, 1st April, 1st July or 1st October).
Putting the two together, the Sunday on-or-just-before the first day of the quarter is given by TRUNC( TRUNC( date_value, 'Q' ) + 1, 'IW' ) - 1
Therefore, the number of days between the Sunday on-or-just-before the start of the quarter and the Sunday on-or-just-before a given date is: ( TRUNC( date_value + 1, 'IW' ) - 1 ) - ( TRUNC( TRUNC( date_value, 'Q' ) + 1, 'IW' ) - 1 ) - which can be simplified by cancelling the -1 terms.
The number of weeks difference is just that number divided by 7 (but gives a 0-indexed value and you want the week number of the quarter to be 1-indexed; you either add 1 week to the result or, prior to doing the division, add 7 days).