I want to write a query where it displays data between 01-April-2010 to lastday-april-2011.
But I don't want to hard code the year. It should take from system date so it only displays records from this year april to next year april.
Thanks in advance for the help.
select add_months( trunc(sysdate,'YYYY'), -12 )
+ interval '4' month
+ level
- 1
from dual
connect by level <= ( (trunc(sysdate,'YYYY')
+ interval '4' month) -
(add_months( trunc( sysdate, 'YYYY' ), -12 )
+ interval '4' month) )
should work. You could probably simplify the expression that computes the number of rows but I'd have to think for a few minutes about leap years.
If the date column has no time component:
select ...
from mytable
where datecol between add_months(trunc(sysdate,'YYYY'),3)
and add_months(trunc(sysdate,'YYYY'),16)-1
If the date column has a time component:
select ...
from mytable
where datecol >= add_months(trunc(sysdate,'YYYY'),3)
and datecol < add_months(trunc(sysdate,'YYYY'),16)
Your query should be something like this
SELECT *
FROM youtable
WHERE datecolumn BETWEEN to_char(sysdate,'yyyy')+'0401' AND to_char(sysdate,'yyyy')+'0430'
Related
I am looking to obtain all data in a table from yesterday in SQL Oracle.
This is simply enough using the WHERE clause, i.e,
SELECT *
FROM My_Data
WHERE TO_DATE(My_Data.Date,'YYYY-MM-DD') = TRUNC(SYSDATE)-1
However if I now need to add more logic where if the day of the query is a Monday (SYSDATE) then obtain data between Friday and Sunday.
Using a between statement is no issue, I'm just not sure if I can include in a where statement given I'm unable to use case statement here.
Thanks
SELECT
*
FROM
My_Data
WHERE
TO_DATE(My_Data.Date,'YYYY-MM-DD')
Between Case When To_Char(SYSDATE, 'DY') = 'MON' Then TRUNC(SYSDATE)-3 ELSE TRUNC(SYSDATE)-1 END
And TRUNC(SYSDATE)-1
You can use the Case expression in Where clause. Regards...
Don't use TO_DATE on a column that is already a date (and if it is a string then don't store dates as strings).
So you are not dependent on the date language session parameter, you can compare the date to the start of the ISO week (which is independent of language) and you can compare on a date range so that Oracle can use an index on your date column:
SELECT *
FROM My_Data
WHERE "DATE" < TRUNC(SYSDATE)
AND "DATE" >= CASE TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW')
WHEN 0 -- Monday
THEN TRUNC(SYSDATE) - 3
ELSE TRUNC(SYSDATE) - 1
END;
or:
SELECT *
FROM My_Data
WHERE "DATE" < TRUNC(SYSDATE)
AND ( ( TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW') = 0 AND "DATE" >= TRUNC(SYSDATE) - 3 )
OR "DATE" >= TRUNC(SYSDATE) - 1
);
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';
I want to fetch data of last 4 quarter including current quarter.
Suppose if I run the query on 30-MAR-2019 then I want data from 01-APR-2018 to 31-MAR-2019
and if I run the query on 01-apr-2019 then I want data between 01-JUL-2018 and 30-JUN-2019
Could you please help me on the same
The tricky part is getting the last day of the quarter.
This solution calculates the starting day of the range by subtracting 9 months from the target date and then truncating with the 'Q' mask which gives us the first day of the quarter. We then calculate that date again, subtract one day then add twelve months and that gives the last day of the current quarter:
with tgt as ( select date '2019-03-30' as dt from dual
union all select date '2019-02-28' as dt from dual
union all select date '2019-04-01' as dt from dual
)
select trunc(tgt.dt - interval '9' month, 'Q') as range_st,
(trunc(tgt.dt - interval '9' month, 'Q') - 1) + interval '12' month as range_end
from tgt
/
There may be a slicker solution out there, but this is the end of my coffee break :)
this will work:
select TRUNC(sysdate+1, 'Q') - interval '9' month,TRUNC(sysdate+1, 'Q') +
interval '3' month -1
from dual ;
01-JUL-2018 30-JUN-2019
select TRUNC(to_date('30-MAR-2019')+1, 'Q') - interval '9'
month,TRUNC(to_date('30-MAR-2019')+1, 'Q') + interval '3' month -1
from dual ;
01-APR-2018 31-MAR-2019
This is dynamically:
With param as (
Select
to_date(extract(year from add_months(sysdate,-12)) ||
lpad((floor(extract(month from add_months(sysdate,-12))/3)*3)+1,2, '0') || '01',
'yyyymmdd') first_date
from dual
)
Select
level quartal,
Add_months(first_date, ((level-1)*3)) from_dat,
Last_day(add_months(first_date, ((level-1)*3)+3)-1) to_dat
From param
connect by level <= 4;
You can do:
select (trunc(sysdate, 'Q') + interval '3' month) as next_quarter_start,
(trunc(sysdate, 'Q') + interval '15' month) - interval '1' day as next_quarter_end
from dual;
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;