Is there any way i can calculate the first and last day of the three quarters in any year . 2012 , 2013 or 2014
SELECT ADD_MONTHS(TRUNC(SYSDATE, 'Q'), -3) AS First,
TRUNC(SYSDATE, 'Q') - 1 AS Last
FROM DUAL
calculates the first quarter of current year. i want to calculate the first quarter of any year ?
You could do the following:
with q(qtr) as(
select add_months(
DATE '2013-01-01'
, (level-1)*3
)
from dual
connect by level <= 4
)
select qtr as first_day
, last_day(add_months(qtr, 2)) as last_day
from q
Result:
FIRST_DAY LAST_DAY
----------- -----------
01.01.2013 31.03.2013
01.04.2013 30.06.2013
01.07.2013 30.09.2013
01.10.2013 31.12.2013
SQLFIddle Demo
This is one way of doing it
select to_date('01-JAN-'||to_char(yr), 'DD-MON-YYYY') first_qtr,
to_date('01-APR-'||to_char(yr), 'DD-MON-YYYY') second_qtr,
to_date('01-JUL-'||to_char(yr), 'DD-MON-YYYY') third_qtr,
to_date('01-OCT-'||to_char(yr), 'DD-MON-YYYY') fourth_qtr
from ( select :year yr from dual )
UNION ALL
select to_date('01-APR-'||to_char(yr), 'DD-MON-YYYY')-1 first_qtr,
to_date('01-JUL-'||to_char(yr), 'DD-MON-YYYY')-1 second_qtr,
to_date('01-OCT-'||to_char(yr), 'DD-MON-YYYY')-1 third_qtr,
to_date('01-JAN-'||to_char(yr+1), 'DD-MON-YYYY')-1 fourth_qtr
from ( select :year yr from dual )
I have used bind variables so change it to your requirements accordingly.
I am fairly new to Oracle, so other's can give a simplified code.
The output when given 2009 would be as below
FIRST_QTR SECOND_QTR THIRD_QTR FOURTH_QTR
01/01/2009 04/01/2009 07/01/2009 10/01/2009
03/31/2009 06/30/2009 09/30/2009 12/31/2009
This is an old question but maybe this will be helpful:
WITH y1 AS (
SELECT LEVEL + 2000 AS the_year
FROM dual
CONNECT BY LEVEL <= 20
), q1 AS (
SELECT LEVEL AS the_quarter
FROM dual
CONNECT BY LEVEL <= 4
)
SELECT the_year, the_quarter
, TO_CHAR(first_day, 'DAY') AS first_dw, first_day
, TO_CHAR(last_day, 'DAY') AS last_dw, last_day
FROM (
SELECT the_year, the_quarter
, ADD_MONTHS(TO_DATE(the_year, 'YYYY'), 3 * (the_quarter - 1)) AS first_day
, ADD_MONTHS(TO_DATE(the_year, 'YYYY'), 3 * the_quarter) - 1 AS last_day
FROM y1, q1
)
One line per year, each line consisting of the year plus 8 (=2 dates per quarter) dates:
with params as (
select
2012 as start_year,
2014 as end_year
from
dual
)
select
start_year+ level - 1 year,
to_date((start_year+ level - 1) || '0101', 'yyyymmdd') start_q1,
to_date((start_year+ level - 1) || '0331', 'yyyymmdd') end_q1 ,
to_date((start_year+ level - 1) || '0401', 'yyyymmdd') start_q2,
to_date((start_year+ level - 1) || '0630', 'yyyymmdd') end_q2 ,
to_date((start_year+ level - 1) || '0701', 'yyyymmdd') start_q3,
to_date((start_year+ level - 1) || '0930', 'yyyymmdd') end_q3 ,
to_date((start_year+ level - 1) || '1001', 'yyyymmdd') start_q4,
to_date((start_year+ level - 1) || '1231', 'yyyymmdd') end_q4
from
dual, params
connect by
start_year + level -1 <= end_year;
Related
I have the following query which gives the second and fourth Saturdays of the previous month along with all the Sundays of the previous month:
SELECT to_char(NEXT_DAY(NEXT_DAY(NEXT_DAY(NEXT_DAY(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1, 'SATURDAY'), 'SATURDAY'),'SATURDAY'),'SATURDAY'),'YYYYMMDD') SECOND_SATURDAY
FROM DUAL
UNION ALL
SELECT to_char(NEXT_DAY(NEXT_DAY(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1, 'SATURDAY'),'SATURDAY'),'YYYYMMDD') SECOND_SATURDAY
FROM DUAL
UNION ALL
select distinct day_date from
(SELECT to_char(NEXT_DAY(LEVEL + TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH') - 1,'SUNDAY'),'YYYYMMDD') day_date
FROM DUAL
CONNECT BY LEVEL <= ADD_MONTHS(TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH'), 1) - TRUNC((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL), 'MONTH'))
where substr(day_date,1,6) in (select to_char((SELECT LAST_DAY(ADD_MONTHS(sysdate,-1)) FROM DUAL),'YYYYMM') from dual)
But I feel there must be a simpler way to get the same result in oracle.Any help in this regard is welcome. My requirement for the date format is 'YYYYMMDD'.
Edited because I misunderstood the question:
I think you want something like the following:
SELECT TO_CHAR(my_date, 'YYYYMMDD') AS my_formatted_date
FROM (
SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2))+7, 'SATURDAY') AS my_date
FROM dual
UNION ALL
SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2))+21, 'SATURDAY')
FROM dual
UNION ALL
SELECT NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY') + (LEVEL-1)*7
FROM dual
CONNECT BY NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY') + (LEVEL-1)*7 < TRUNC(SYSDATE, 'MONTH')
);
In the first part of the query I determine the last day of the previous month and then get the first Saturday that falls after at least one week after that date (the second Saturday of the month will be anywhere from the 8th to the 14th). Then I get the first Saturday falling at least three weeks after the last day of the previous month (the fourth Saturday will be anywhere from the 22nd to the 28th). Last, I loop over the Sundays of the previous month, starting from the first Sunday falling after the last day of the month previous to that (that is, two months ago). You could also use NEXT_DAY(TRUNC(ADD_MONTHS(SYSDATE, -1) - 1), 'SUNDAY') instead of NEXT_DAY(LAST_DAY(ADD_MONTHS(SYSDATE, -2)), 'SUNDAY')
MY_FORMA
--------
20190209
20190223
20190203
20190210
20190217
20190224
6 rows selected.
For instance like here:
with
t1 as (select add_months(trunc(sysdate, 'month'), -1) dt from dual),
t2 as (
select dt + level - 1 dt, to_char(dt + level - 1, 'dy', 'nls_date_language=english') dy
from t1 connect by dt + level - 1 < trunc(sysdate, 'month'))
select to_char(dt, 'yyyymmdd') dt, dy
from (
select dt, dy, sum(case when dy = 'sat' then 1 end) over (order by dt) sm from t2)
where dy = 'sun' or (dy = 'sat' and sm in (2, 4))
Result:
DT DY
-------- ---
20190203 sun
20190209 sat
20190210 sun
20190217 sun
20190223 sat
20190224 sun
I generated all days for previous month, assigned english day names, conditionally counted saturdays and showed only interesting dates.
Edit:
This works but is there any way to get around the with clause since my
parent query is of the from: with x as ( .... where date in ("required
days") and ...) . So it presents a nested with situation.
Yes, you can convert it easily, for example like here:
select to_char(dt, 'yyyymmdd') dt
from (
select dt, dn, rank() over (order by mod(dn, 6), dt) rnk
from (
select d + level - 1 dt, d + level - trunc(d + level - 1, 'iw') dn
from (select add_months(trunc(sysdate, 'month'), -1) d from dual)
connect by level <= add_months(d, 1) - d))
where dn = 7 or (dn = 6 and rnk in (2, 4))
dbfiddle demo
with clause made steps more readable. Now I also used day numbers and mod() for counting, just to show different approaches, but you can use whatever is clearer for you (day names, sum or count instead of rank).
Oracle (SQL) - I have 3 available dates in a month (1st, 10th and 25th). I need a query to find out the closest among the 3 dates based on the date of executing my query. For e.g, when i run the query on 4th, i should get 10th as my result, when i run on 12th, the result should be 25th and when i run on 27th, the result should be the 01st of next month.
I am struggling with the logic. Please help..
with
inputs ( dt ) as (
select to_date( '03/24/2015 11:30:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
select to_date( '08/03/2016 07:15:00', 'mm/dd/yyyy hh24:mi:ss') from dual union all
select to_date( '02/29/2016 22:30:00', 'mm/dd/yyyy hh24:mi:ss') from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select dt,
case when extract(day from dt) < 10 then trunc(dt, 'mm') + interval '9' day
when extract(day from dt) < 25 then trunc(dt, 'mm') + interval '24' day
else add_months(trunc(dt, 'mm'), 1)
end as next_std_dt
from inputs;
DT NEXT_STD_DT
------------------- -------------------
03/24/2015 11:30:00 03/25/2015 00:00:00
08/03/2016 07:15:00 08/10/2016 00:00:00
02/29/2016 22:30:00 03/01/2016 00:00:00
I believe this is much more efficient and simpler than the other solutions.
WITH
possible_dates
AS
-- generate the three available dates for the current month
(SELECT TRUNC (SYSDATE, 'MM') available_date
FROM DUAL
UNION ALL
SELECT TRUNC (SYSDATE, 'MM') + 9
FROM DUAL
UNION ALL
SELECT TRUNC (SYSDATE, 'MM') + 24
FROM DUAL
UNION ALL
SELECT ADD_MONTHS (TRUNC (SYSDATE, 'MM'), 1)
FROM DUAL),
delta
AS
-- calculate the distance of those available dates
(SELECT (available_date - SYSDATE) diff, available_date
FROM possible_dates)
SELECT *
FROM delta
WHERE diff = (SELECT MIN (diff)
FROM delta
WHERE diff >= 0);
If using PL SQL is an option, then use the query as following:
`DECLARE
curr_month CHAR(2);
curr_year CHAR(4);
future_date DATE;
BEGIN
select to_char(sysdate, 'MM') INTO curr_month from dual;
select to_char(sysdate, 'YYYY') INTO curr_year from dual;
future_date := TO_DATE('12' || curr_month || curr_year, 'DD/MM/YYYY');
IF (SYSDATE > future_date) THEN
{..whatever you want to do...}
ELSIF (SYSDATE > future_date2) THEN
{..whatever you want to do...}
END IF;
END;`
WITH mytable(dt) AS
(SELECT '01'
FROM dual
UNION ALL SELECT '10'
FROM dual
UNION ALL SELECT '25'
FROM dual),
given_dates AS
(SELECT Trunc (To_date (dt || To_char(sysdate, 'MMYYYY'), 'DDMMYYYY')) dt,
Trunc(sysdate) cdate
FROM mytable),
comp AS
(SELECT cdate,
CASE
WHEN ABS (cdate - dt) < ABS (cdate - Add_months (dt, 1)) THEN dt
ELSE Add_months (dt, 1)
END dt_comp
FROM given_dates)
SELECT dt_comp closest_date
FROM
(SELECT dt_comp,
rank() OVER (
ORDER BY ABS (cdate - dt_comp)) rn
FROM comp)
WHERE rn = 1;
With the code below I can return this month and past 6 months.
My code:
SELECT TO_CHAR(add_months(TRUNC(to_date( sysdate),'Month'), -rownum+1), 'Month') mon,
rownum month_order
FROM dual
CONNECT BY rownum <=
(SELECT COUNT(mon)
FROM
(SELECT TO_CHAR( add_months( start_date, level-1 ), 'fmMonth' ) AS mon
FROM
(SELECT to_date( add_months(TRUNC(sysdate),-6)) start_date,
to_date( sysdate) end_date
FROM dual)
CONNECT BY level <= months_between( TRUNC(end_date,'MM'), TRUNC(start_date,'MM') ) + 1) dual);
In the same way I have to return this date and past 9 dates.
Please help me on this to return 10 dates by using connect by.
Thanks in advance.
Here's a query for the last ten days.
select sysdate - (level-1)
, level as day_order
from dual
connect by level <= 10;
Your month query seems extremely over-engineered. This would do the same thing:
select to_char(add_months(trunc(sysdate, 'MM'), 1 - level), 'Month')
, level as month_order
from dual
connect by level <= 7;
"Let suppose if the data is available on today's date and remaining 9 date's doesn't have any data but it has to display the count as zero"
Use the generated result set in an outer join:
with q as (
select sysdate - (level-1) as dt
, level as day_order
from dual
connect by level <= 10
)
select q.dt as txn_date
, sum(t42.col1)
from q
left outer join t42
on t42.transaction_date = q.dt
group by q.dt;
Try this -
SELECT ( TRUNC( SYSDATE ) + 1 ) - ROWNUM
FROM DUAL
CONNECT BY ROWNUM <= 10
In the same way i have to return this date and past 9 dates.
This will get today and the past 9 days:
SELECT TRUNC( SYSDATE ) - LEVEL + 1 AS day
FROM DUAL
CONNECT BY LEVEL <= 10
this month and past 6 months
SELECT TO_CHAR( ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 1 - LEVEL ), 'Month' ) AS month
FROM DUAL
CONNECT BY LEVEL <= 7
how to get previous 11 month names from sysdate using oracle
i tried like , iam getting month names between some dates
select add_months (trunc (to_date('10/18/2007','MM/DD/YYYY'), 'MM'), 1*Level -1)
Month FROM Dual
CONNECT BY Level <= MONTHS_BETWEEN(to_date('11/17/2008','MM/DD/YYYY'), to_date('10/18/2007','MM/DD/YYYY')) + 1
order by month
May be you need something like that:
select to_char(add_months (to_date('10/18/2007','MM/DD/YYYY'), -1* Level), 'Mon-YYYY')
Month
FROM Dual
CONNECT BY Level <= 11
order by month
YOU CAN USE THIS:
SELECT TO_CHAR( ADD_MONTHS(SYSDATE,-1*LEVEL ),'MON') MONTH_NAME
FROM DUAL
CONNECT BY LEVEL <= MONTHS_BETWEEN( TRUNC(SYSDATE,'MM') , ADD_MONTHS( TRUNC(SYSDATE,'MM'),-11))
ORDER BY LEVEL
I have
Year : 2011
Month: Nov
Day: Sun
WeekNumber(Monthwise): 4
Desire Output:
Date
--------
2011-11-20
How can I do so in a single SQL statement?
Thanks
I'd probably look at using the NEXT_DAY function which returns the first day of the weekday provided that occurs after the date given. Once you've got that, you can then add the required number of weeks.
An example of this might be:
with test_data as (
select
'2011' as the_year,
'Nov' as the_month,
'Sun' as the_day,
4 as the_week
from dual
)
select
the_year, the_month, the_day, the_week,
next_day(to_date(the_year||the_month, 'YYYYMON') - 1, the_day) +
7* (the_week -1) as the_date
from test_data
this may work.
SELECT NEXT_DAY( TO_DATE(TO_CHAR((4-1)*7) || '-' || 'NOV' || '-' || '2011','dd-mon-yyyy') ,'Sun')
FROM DUAL
see: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions093.htm
try :
SELECT A.B + B.D YourDate
FROM (SELECT TO_DATE (Your4DigitYear || LPAD ( YourMonth, 2, '0' ) || LPAD ( DECODE (YourWeekOfMonth, 1, '1', (YourWeekOfMonth - 1) * 7 ), 2, '0' ), 'YYYYMMDD') B FROM DUAL) A, (SELECT LEVEL - 1 D FROM DUAL CONNECT BY LEVEL < 15) B WHERE
TO_CHAR (A.B + B.D, 'D' ) = YourDayOfWeek AND
TO_CHAR (A.B + B.D, 'W' ) = YourWeekOfMonth;