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().
Related
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.
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
I need to analyze an SQL query (and construct its equivalent in MDX). I'm not familiar with SQL and can't access the database, so there are 5 simple things I can't figure out:
What does the part WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 mean? Specifically:
What does subtracting 7 from trunc(SYSDATE, 'iw') do? Subtract 7 weeks or 7 days? I understand the trunc(...) expression is a value 0-53 corresponding to the week of the year, but it seems to clash with the label "previous week" and stated purpose of the query.
How does SQL compare dates? Are the values from trunc(...) evaluated as dates during comparison?
The query seems to group rows together if they happened in the same minute. However, the few rows of output I can see have 10-minute granularity (00:00, 00:10, 00:20, etc.) Is there something in the query that groups rows into 10 minute intervals, or is this a result of the input data?
Why are calls to substr() and to_char() and needed in the group by condition? What would happen if trunc(idate, 'HH24:MI') was used instead?
What does the pm do? There is also a cm that seems to have a similar function. Are these part of the temporary table names?
Finally, how do the hash marks (#) affect this query? I read it might be to signify temporary tables. If so, are these temporary tables created manually, or does something in the query cause them to be created?
For reference here is the query. (On a Oracle database, if it makes any difference.) Its purpose is to "analyze how firewall accept events are trending compared to last week":
SELECT 'Previous Week Average' AS term ,
Substr(To_char(idate, 'HH24:MI'), 0, 4)
|| '0' AS event_time ,
Round(Avg(tot_accept)) AS cnt
FROM (
SELECT *
FROM st_event_100_#yyyymm-1m#
WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 #stat_monitor_group_query#
UNION ALL
SELECT *
FROM st_event_100_#yyyymm#
WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 #stat_monitor_group_query# ) pm
GROUP BY substr(to_char(idate, 'HH24:MI'), 0, 4)
|| '0'
UNION ALL
SELECT 'Today' AS term ,
substr(to_char(idate, 'HH24:MI'), 0, 4)
|| '0' AS event_time ,
round(avg(tot_accept)) AS cnt
FROM st_event_100_#yyyymm# cm
WHERE idate >= trunc(SYSDATE) #stat_monitor_group_query#
GROUP BY substr(to_char(idate, 'HH24:MI'), 0, 4)
|| '0'
ORDER BY term DESC,
event_time ASC
iw truncates the date to the first day of the calendar week as defined by the ISO 8601 standard, which is Monday. When you subtract numbers from the date, it is always the number of days. So, idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 gives you those dates that fall between previous week's Monday and Friday.
to_char(idate, 'HH24:MI') gives you the time(hour and minute) part in 24hr format. Ex: 14:33. By using substrin to extract only 4 characters, you are actually getting 14:3. So yes, this groups with a granularity of 10 mins.
You cannot write trunc(idate, 'HH24:MI'). It can only have 1 precision specifier.
If you write trunc(idate,'HH24'), it truncates to the hour. If you use MI, it truncates to the minute. So, to truncate it to 10 mins is a little tricky.
pm is just an alias for the whole subquery.
SELECT *
FROM st_event_100_#yyyymm-1m#
......
WHERE idate BETWEEN trunc(SYSDATE, 'iw')-7 AND trunc(SYSDATE, 'iw')-3 #stat_monitor_group_query#
# is part of the table anme in your query. It has no significance as such. But, it might be project/company specific.
What this is doing is selecting all columns from TABLE where a specific date time column is between last Sunday and this coming Saturday, 7 days total (no matter what day of the week you are running the query on)
I would like to have help converting the below statement into Oracle since I found out that it will not work on Oracle.
SELECT *
FROM TABLE
WHERE DATE_TIME_COLUMN
BETWEEN
current date - ((dayofweek(current date))-1) DAYS
AND
current date + (7-(dayofweek(current date))) DAYS
After poking around a bit more I was able to find something that worked for my specific problem with no administrator restrictions for whatever reason:
SELECT *
FROM TABLE
WHERE DATE_TIME_COLUMN
BETWEEN
TIMESTAMPADD(SQL_TSI_DAY, DayOfWeek(Current_Date)*(-1) + 1, Current_Date)
AND
TIMESTAMPADD(SQL_TSI_DAY, 7 - DayOfWeek(Current_Date), Current_Date)
Use TRUNC() to truncate to the start of the week:
SELECT *
FROM TABLE
WHERE DATE_TIME_COLUMN
BETWEEN trunc(sysdate, 'WW')
and
trunc(sysdate + 7, 'WW');
sysdate is the current system date, trunc truncates a data, and WW tells it to truncate to the week (rather than day, year, etc.).
Assuming DATE_TIME_COLUMN is - as it should be - of datatype date, I think this gets what you want.
where DATE_TIME_COLUMN between
next_day(sysdate,'SUNDAY')-7 and next_day(sysdate,'SATURDAY')
You may need to tweak it a bit. Please follow up studying the official docs on the NEXT_DAY function in the relevant docs at http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions106.htm#SQLRF00672
The proposed TRUNC does not guarantee you get the date of a particular day of the week:
SQL> alter session set nls_date_format='day dd-mon-yyyy';
Session altered.
SQL> select trunc(sysdate,'WW') from dual;
TRUNC(SYSDATE,'WW')
---------------------
friday 22-jan-2016
SQL> select trunc(sysdate+7,'WW') from dual;
TRUNC(SYSDATE+7,'WW')
---------------------
friday 29-jan-2016
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;