Identify the day and get the previous date in Oracle SQL - sql

I have below query which gives current date. I want to return the value as String for this reason i used TO_CHAR.
select NVL(TO_CHAR(sysdate,'DD.MM.YYYY'),0) from dual
But i need to identify Day and based on this it should return the previous Date.
For example when the query runs on every Monday it should return the date from last Friday. When the query runs from Tuesday till Friday it should return the date from previous day.
For example when the query runs today it should return the date from last Friday i.e 18.02.2022. When the query runs tommorow it should return the date from Today 21.02.2022.
I want to avoid dates from every Saturday and Sunday. Can we do this in one query ?

If you want to do it so that the query will work in any language and/or territory then you can compare the date to the start of the ISO week:
SELECT TO_CHAR(SYSDATE, 'DD.MM.YYYY') AS today,
CASE TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')
WHEN 0 THEN TO_CHAR(SYSDATE - 3, 'DD.MM.YYYY') -- Monday
WHEN 6 THEN TO_CHAR(SYSDATE - 2, 'DD.MM.YYYY') -- Sunday
ELSE TO_CHAR(SYSDATE - 1, 'DD.MM.YYYY') -- Any other day
END AS previous_weekday
FROM DUAL;
db<>fiddle here

As a slight variation on MTO's answer, just to perhaps make it clearer to a future maintainer, you could use day names or abbreviations instead - but would need to specify the date language (which maybe assumes the hypothetical future maintainer uses, or at least understands, that language):
select to_char(sysdate
- case to_char(sysdate, 'DY', 'NLS_DATE_LANGUAGE=ENGLISH')
when 'MON' then 3
when 'SUN' then 2
else 1
end, 'DD.MM.YYYY') as result
from dual
RESULT
----------
18.02.2022
db<>fiddle, including what you see for a range of 14 days, not just today.

Related

Using Case Statement in Where Clause ___ Using date ranges with BETWEEN

I am trying to filter a date to a specific range depending on whether or not we have passed the first weekday of the current month.
Oracle seems to not like that I am using BETWEEN.
WHEN
TO_DATE(myDate,'YYYYMMDD')=CASE WHEN TO_DATE(SYSDATE-1) - TO_DATE(last_day(add_months(sysdate, -1))+6)>0
THEN
TO_DATE(last_day(add_months(sysdate, -1))+1, 'YYYYMMDD') --AND to_date(TRUNC(SYSDATE) - 1, 'YYYYMMDD')
Else
TO_DATE(last_day(add_months(sysdate, -2))+1, 'YYYYMMDD') --AND to_date(TRUNC(SYSDATE) - 1, 'YYYYMMDD')
END
Please let me know how to correct this.
If you want dates that are equal to or after the first monday of the current month, you can do:
to_date(my_date, 'YYYYMMDD') >= next_day(trunc(sysdate, 'MM') - 1, 'MONDAY')
trunc(sysdate, 'MM') - 1 gives you the last day of the previous month. Then next_day(..., 'MONDAY') gives you the following Monday.
You can change the day name according to what your definition of a week day is. Also, it is worth noting that the day name (the second argument to next_day() must be provided in the language of your session.

Oracle : Query to get the Last Friday of the week if I give any date

If I give a date let's say '13-Mar-2019' my query needs to retrieve the value '15-Mar-2019'. Which is the last Friday of the week.
Trancate the date to the ISO week, which gets you the week's Monday (as an ISO week starts with Monday). Then add four days:
select trunc(date '2019-03-13', 'iw') + 4 from dual;
I would use next_day(). It is the Oracle function specifically designed for this purpose.
select next_day(date '2019-03-13', 'Fri')
from dual;
The only nuance is that if the date is Friday, then it will return the next Friday. That might be what you want. Otherwise, just subtract one day:
select next_day(date '2019-03-13' - 1, 'Fri') as friday_end_of_week
from dual;
Try below -
select trunc(to_date('13-Mar-2019'), 'iw') + 4 from dual
SELECT NEXT_DAY( to_date('2019-03-13', 'yyyy-mm-dd'), to_char(to_date('2019-03-01', 'yyyy-mm-dd'), 'DAY')) FROM dual;
demo

sql query to get only friday dates between two dates

Question: How do i select only friday dates between two dates in oracle
SELECT dates,TO_CHAR(dates,'day-mon-yyyy')
FROM
(SELECT to_date('01-jan-12','dd-mon-yy')+rownum -1 AS dates
FROM addresses
WHERE rownum <= to_date('31-jan-12','dd-mon-yy')- to_date('01-jan-12','dd-mon-yy')+1)
WHERE upper(regexp_substr(TO_CHAR(dates,'day-mon-yy'),'([[:alpha:]])+'))=upper('FRIDAY');
i need Output like:
06-JAN-12 FRIDAY
13-JAN-12 FRIDAY
20-JAN-12 FRIDAY
27-JAN-12 FRIDAY
03-FEB-12 FRIDAY
10-FEB-12 FRIDAY
17-FEB-12 FRIDAY
24-FEB-12 FRIDAY
02-MAR-12 FRIDAY
09-MAR-12 FRIDAY
16-MAR-12 FRIDAY
23-MAR-12 FRIDAY
30-MAR-12 FRIDAY
visit more sql queries: SQL Query Interview Questions
You will get an error from what you posted because the values you've used as the first argument to to_char() aren't enclosed in single quotes:
select to_date(01-jan-12,'dd-mon-yy') from dual;
ORA-00904: "JAN": invalid identifier
Because there are no quotes, jan is interpreted as an identifier, and there is (presumably) no column call JAN in your addresses table. It's also bad practice to use 2-digit years, and where you must (from really old data) it's usually better to use RR than YY. The month names are also affected by your NLS settings, so it's safer to use month numbers than names; if you really want names the to_char() function has a third argument to control the language.
You are doing this in quite a complicated way, and you're relying on the addresses table having enough rows. Specifying that you want the day name in lower case via day instead of DAY, then making it uppercase, then stripping off the bits of the string - that you specified in the first place! - to only get the day name, and then comparing that on the assumption (again) that the NLS settings will give you English day names anyway is... unnecessarily convoluted. As is calling upper() against a fixed string literal you you can (and are) supply in uppercase already.
Instead of
WHERE upper(regexp_substr(TO_CHAR(dates,'day-mon-yy'),'([[:alpha:]])+'))=upper('FRIDAY');
you could do any of these, or other variations:
WHERE regexp_substr(TO_CHAR(dates,'DAY-mon-
y'),'([[:alpha:]])+')=upper('FRIDAY');
WHERE TO_CHAR(dates,'DAY')='FRIDAY ';
WHERE TRIM(TO_CHAR(dates,'DAY'))=upper('FRIDAY');
WHERE TO_CHAR(dates,'FMDAY','NLS_DATE_LANGUAGE=ENGLISH')='FRIDAY';
You could avoid relying on the addresses table by using a hierarchical query, against the dual table:
SELECT next_day(date '2012-01-01' - 1, 'FRIDAY') + (7 * (level - 1))
FROM dual
CONNECT BY next_day(date '2012-01-01' - 1, 'FRIDAY') + (7 * (level - 1))
<= date '2012-03-31';
Using next_day also relies on NLS settings though, so unless you can always control the session date language, it might be safer (if a little less efficient) to get all the dates and then filter them in an NLS-independent way:
SELECT dates, to_char(dates, 'FMDAY')
FROM (
SELECT date '2012-01-01' + level - 1 AS dates
FROM dual
CONNECT BY level <= date '2012-03-31' - date '2012-01-01'
)
WHERE to_char(dates, 'FMDAY', 'NLS_DATE_LANGUAGE=ENGLISH') = 'FRIDAY';
DATES TO_CHAR(DATES,'FMDAY')
--------- ------------------------------------
06-JAN-12 FRIDAY
13-JAN-12 FRIDAY
20-JAN-12 FRIDAY
27-JAN-12 FRIDAY
03-FEB-12 FRIDAY
10-FEB-12 FRIDAY
17-FEB-12 FRIDAY
24-FEB-12 FRIDAY
02-MAR-12 FRIDAY
09-MAR-12 FRIDAY
16-MAR-12 FRIDAY
23-MAR-12 FRIDAY
30-MAR-12 FRIDAY
13 rows selected.
As #mathguy pointed out in a comment, although next_day() is NLS-sensitive, you can use an expression for the second argument, so instead of hard-coding the day name you can do this:
next_day(date '2012-01-01' - 1, to_char(date '1999-12-31', 'FMDAY'))
where 1999-12-31 can be any date known to be a Friday; and if you don't mind the expression in the select list and connect-by clause being different (and really, you - and I - shouldn't!) you can reduce the computational cost of that check with:
SELECT dates, to_char(dates, 'FMDAY', 'NLS_DATE_LANGUAGE=ENGLISH')
FROM (
SELECT next_day(date '2012-01-01' - 1,
to_char(date '1999-12-31', 'FMDAY')) + (7 * (level - 1)) AS dates
FROM dual
CONNECT BY level <= 1 + (date '2012-03-31' - next_day(date '2012-01-01' - 1,
to_char(date '1999-12-31', 'FMDAY')))/7
);
which gets the same 13 rows as above, regardless of the session's date language. If you want the output to be in the session language too, just remove the overriding third argument to to_char().

In Oracle SQL, how to get the time for only this current week?

I have a query , where I want to obtain some data for different time durations (this month, this week, etc).
For the "this week" column, I want it to get all the data from the most recent Monday until now. How would I do this?
I have the following SQL so far :
WHERE prla.CREATION_DATE >= SYSDATE - ?
trunc(sysdate, 'iw') is what you're after. IW is the format mask used for Monday of the week the specified date is in (as Monday is the ISO standard for the start of the week). E.g.:
with dates as (select trunc(sysdate, 'mm') - 10 + level dt
from dual
connect by level <= 40)
select dt
from dates
where dt >= trunc(sysdate, 'iw')
and dt <= sysdate; -- only needed if the dates in the column could be beyond now.
Yeah that will do: But it is better to use sysdate-8. Because if the current day is same as your searching day, it will return the current date. For Eg.
select next_day(sysdate-7,'WED') from dual;
OUTPUT
19-AUG-15
Whereas the below one will give you the last week
select next_day(sysdate-8,'WED') from dual;
OUTPUT
12-AUG-15
You should truncate the current date.
TRUNC(SYSDATE, 'DAY')
This should give you the first day of the week, which is Monday in lot of countries.
If it's giving you the previous Sunday instead you should do this.
TRUNC(SYSDATE, 'DAY')+1
I found out to do this now:
select next_day (sysdate-7, 'MONDAY') Last_Monday from dual;
So in my case, we can remove the SYSDATE subtraction and it is simply :
prla.CREATION_DATE >= next_day (sysdate-7, 'MONDAY')
source

In oracle SQL, how would you obtain the timestamp representing the start of the week?

I'm using an Oracle 9i database and want to obtain, within a function, the timestamp representing the start of the week, i.e. The most recent monday, at 00:00:00.
I am aware that the timestamp representing the start of the current day is TO_TIMESTAMP(SYSDATE).
You can use the function next_day to get that:
SQL> select next_day(sysdate-7, 'MONDAY') FROM DUAL;
NEXT_DAY
---------
29-APR-13
Getting the start of the week should work with trunc (see docs).
So,
select to_timestamp(trunc(sysdate, 'D')) from dual
should work.
However, depending on your NLS settings, the first day of the week for oracle may well be Sunday.
this appears to return Monday before the day of week in question at midnight. to prove out just play around with sysdate and subtract days...
select case when to_Char(sysdate,'d') = 1 then
trunc(sysdate-6)
else
trunc(sysdate - (to_Char(sysdate,'d')-2))
END
from dual;
You can truncate a date to Monday with:
select trunc(sysdate, 'IW') FROM DUAL;