Getting Month values for specific year - sql

Fisc_prd stands for month
fisc_yr stands for year
I need the result in such a way that if current month is 01(that is Jan) then i need all the period for previous year i.e 1 to 12 and if the current month is not equal to 01 then i need all the period for current year less than current month(e.g if the current month is 3 then i need 1 to 2 as fisc_prd)
I can only get all the fisc_prd for previous year but cant get fisc_prd less than current month for current year. In Below query, CALENDAR table contains all the Month and Year values.By usig this query i can get all the fisc_prd for previous year when current month is 01.
SELECT FISC_PRD,FISC_YR FROM CALENDAR WHERE FISC_YR=(SELECT DECODE(TO_NUMBER(TO_CHAR(SYSDATE,'MM')),01,(TO_NUMBER(TO_CHAR(SYSDATE,'YYYY'))-1) ,TO_NUMBER(TO_CHAR(SYSDATE,'YYYY'))) FROM DUAL)
Please share your ideas

If you're basing this on the current date then you can use a connect-by hierarchical query to get the period and year:
select extract(month from add_months(sysdate, 1-level)) as fisc_prd,
extract(year from add_months(sysdate, 1-level)) as fisc_year
from dual
where level > 1
connect by level <= case when extract(month from sysdate) = 1 then 13
else extract(month from sysdate) end;
Today that gives:
FISC_PRD FISC_YEAR
---------- ----------
1 2015
To check how it behaves for other dates you can use a modified version that uses a specific date but the same logic; I'm using a bind variable here:
variable dt varchar2;
exec :dt := '2015-01-17';
select extract(month from add_months(to_date(:dt, 'YYYY-MM-DD'), 1-level)) as fisc_prd,
extract(year from add_months(to_date(:dt, 'YYYY-MM-DD'), 1-level)) as fisc_year
from dual
where level > 1
connect by level <= case
when extract(month from to_date(:dt, 'YYYY-MM-DD')) = 1 then 13
else extract(month from to_date(:dt, 'YYYY-MM-DD'))
end;
FISC_PRD FISC_YEAR
12 2014
11 2014
10 2014
9 2014
8 2014
7 2014
6 2014
5 2014
4 2014
3 2014
2 2014
1 2014
Changing the value of dt seems to give the result you described; for example with
exec :dt := '2015-03-17';
you get:
FISC_PRD FISC_YEAR
---------- ----------
2 2015
1 2015
But this is just to test the logic, you can just use sysdate rather than a bind variable.
The 1-level and using 13 if the current month is January are because you don't want the current month to be included in the result.

This ought to work:
with sample_data as (select to_number(to_char(add_months(sysdate, 6 - level), 'mm')) fisc_prd,
to_number(to_char(add_months(sysdate, 6 - level), 'yyyy')) fisc_yr
from dual
connect by level <= 24)
select fisc_prd,
fisc_yr
from sample_data
where case when to_char(sysdate, 'mm') = '01' then to_number(to_char(sysdate, 'yyyy')) -1
else to_number(to_char(sysdate, 'yyyy')) end = fisc_yr
and case when to_char(sysdate, 'mm') = '01' then 13
else to_number(to_char(sysdate, 'mm')) end > fisc_prd;

If your colum "FISC_YR" is datetime datatype then the below query will works for you
SELECT FISC_PRD,FISC_YR
FROM CALENDAR
WHERE
(month(getdate())!=1 AND month(FISC_YR) in(month(getdate())- 1,month(getdate())-2) AND year(getdate())=year(FISC_YR))
OR
(month(getdate())=1 AND year(getdate())-1=year(FISC_YR))

Related

SQL Showing Rolling 4 Months, Looking for Fiscal Year

I have been provided the below SQL query and am looking to modify it. Currently this is only pulling the last 4 months worth of data. I am trying to modify it to run from December 1 through the current month. If anyone is able to guide me through this, that would be greatly appreciated.
Select NVL(x.COUNT, 0) + z.COUNT As "Number of RMAs",
Case z.MONTH When 1 Then 'Jan.' When 2 Then 'Feb.' When 3 Then 'Mar.'
When 4 Then 'Apr.' When 5 Then 'May' When 6 Then 'Jun.' When 7 Then 'Jul.'
When 8 Then 'Aug.' When 9 Then 'Sep.' When 10 Then 'Oct.'
When 11 Then 'Nov.' When 12 Then 'Dec.' Else 'error' End As "Month",
z.YEAR,
'28.00' As GOAL,
Round(Avg(NVL(x.COUNT, 0) + z.COUNT) Over (Order By z.YEAR, z.MONTH Rows
Between 2 Preceding And Current Row), 2) As ROLL3MOAVG
From (Select Count(RMA.ID) As count,
Extract(Month From RMA.RMA_DATE) As month,
Extract(Year From RMA.RMA_DATE) As year
From RMA,
(Select Unique RMA_DETAIL.RMA_ID
From RMA_DETAIL
Where RMA_DETAIL.RETURN_CODE_ID > 0 And RMA_DETAIL.RETURN_CODE_ID <
100) RMA_DETAIL
Where RMA.ID = RMA_DETAIL.RMA_ID And RMA.RMA_DATE >= SysDate - 400
Group By Extract(Month From RMA.RMA_DATE),
Extract(Year From RMA.RMA_DATE)) x,
(Select 0 As count,
Extract(Month From Add_Months(SysDate - 120, (Level - 1))) As month,
Extract(Year From Add_Months(SysDate - 120, (Level - 1))) As year
From dual
Connect By Level <= 13) z
Where z.MONTH = x.MONTH(+) And z.YEAR = x.YEAR(+)
Order By z.YEAR,
z.MONTH
Don't have access to any sample data, so I would try the following: The correlated subquery aliased as "z" calculates your date boundaries:
SELECT 0 AS count,
EXTRACT(MONTH FROM Add_Months(SysDate - 120, (LEVEL - 1))) AS month,
EXTRACT(YEAR FROM Add_Months(SysDate - 120, (LEVEL - 1))) AS year
FROM dual
CONNECT BY LEVEL <= 13
COUNT MONTH YEAR
---------- ---------- ----------
0 2 2020
0 3 2020
0 4 2020
0 5 2020
0 6 2020
0 7 2020
0 8 2020
0 9 2020
0 10 2020
0 11 2020
0 12 2020
0 1 2021
0 2 2021
It starts with the month 120 days ago (SysDate - 120) and adds 12 month rows. Run this query in sqldeveloper to check what it does. You'll see it starts in feb 2020 and ends in feb 2021.
If you replace that query with a query that starts on dec 1st up till now it should work:
SELECT 0 AS count,
EXTRACT(MONTH FROM ADD_MONTHS(TO_DATE('01-DEC-2019','DD-MON-YYYY'), (LEVEL - 1))) As month,
EXTRACT(YEAR FROM ADD_MONTHS(TO_DATE('01-DEC-2019','DD-MON-YYYY'), (LEVEL - 1))) As year
FROM dual
CONNECT BY LEVEL <= ROUND(MONTHS_BETWEEN(SYSDATE,TO_DATE('01-DEC-2019','DD-MON-YYYY'))) + 1
COUNT MONTH YEAR
---------- ---------- ----------
0 12 2019
0 1 2020
0 2 2020
0 3 2020
0 4 2020
0 5 2020
0 6 2020
explanation:
start with ADD_MONTHS(TO_DATE('01-DEC-2019','DD-MON-YYYY'), (LEVEL - 1)). Your first row will be LEVEL 1 so this will return December.
CONNECT BY LEVEL <= ROUND(MONTHS_BETWEEN(SYSDATE,TO_DATE('01-DEC-2019','DD-MON-YYYY'))) + 1: add a month up til current month so calculate the number of months between now and dec 1st and add 1.
For getting a query that works for every year (there must be cleaner ways to write this but I can't think of any now), use the following:
SELECT 0 AS count,
EXTRACT(MONTH FROM ADD_MONTHS(TO_DATE('01-DEC-'||TO_CHAR(ADD_MONTHS(SYSDATE,-11),'YYYY'),'DD-MON-YYYY'), (LEVEL - 1))) As month,
EXTRACT(YEAR FROM ADD_MONTHS(TO_DATE('01-DEC-'||TO_CHAR(ADD_MONTHS(SYSDATE,-11),'YYYY'),'DD-MON-YYYY'), (LEVEL - 1))) As year
FROM dual
CONNECT BY LEVEL <= ROUND(MONTHS_BETWEEN(SYSDATE,TO_DATE('01-DEC-'||TO_CHAR(ADD_MONTHS(SYSDATE,-11),'YYYY'),'DD-MON-YYYY'))) + 1

Count in sql birthday on a weekend

I'm trying to write a program in pl/sql (oracle) that must calculate how many times someone 's birthday was on a weekend.
This is what i got, but im missing somthing like an extraction at everyloop (-1 year) from 2018 to 1990 for example.
Can someone help me out please?
SET SERVEROUTPUT ON;
DECLARE
v_counter number default 0;
v_real_birthdate date default to_date('01/01/1990', 'DD/MM/YYYY');
v_birthdate date default to_date('01/01/2018', 'DD/MM/YYYY');
BEGIN
WHILE v_counter < 28
LOOP
v_leeftijd := v_leeftijd +1;
dbms_output.put_line( ( TO_CHAR( v_birthdate, 'DAY' ) ) );
END LOOP;
END;
If we suppose that I was born on today's day 2010 (which would then be 2010-09-12 (yyyy-mm-dd)), the result would be as follows, step by step.
MY_BIRTHDAY represents what we agreed to be my birthday
YEARS uses hierarchical query and produces my birthdays from 2010 to current year (2018)
DAYS extracts day name from my birthday for every year, using English language
the final result filters out weekends (sat, sun)
If you're interested in finding out what every CTE returns, run it one by one and you'll see.
SQL> with
2 my_birthday as
3 (select date '&par_birthday' birthday from dual),
4 years as
5 (select to_date((extract(year from birthday) + level - 1) ||'-'||
6 case when to_char(birthday, 'mm-dd') = '02-29' then '02-28'
7 else to_char(birthday, 'mm-dd')
8 end,
9 'yyyy-mm-dd'
10 ) birthday_yr
11 from my_birthday
12 connect by level <= extract(year from sysdate) -
13 extract(year from birthday) + 1
14 ),
15 days as
16 (select birthday_yr,
17 to_char(birthday_yr, 'dy', 'nls_date_language=english') dy
18 from years
19 )
20 select birthday_yr, dy
21 from days
22 where dy in ('sat', 'sun');
Enter value for par_birthday: 2010-09-12
BIRTHDAY_Y DY
---------- ---
2010-09-12 sun
2015-09-12 sat
SQL> /
Enter value for par_birthday: 2012-02-29
BIRTHDAY_Y DY
---------- ---
2015-02-28 sat
2016-02-28 sun
SQL>
You can use the following query (assuming Feb 06, 1981 is the birthday):
WITH b AS (SELECT TO_DATE('02/06/1981', 'MM/DD/RRRR') birthday FROM dual)
SELECT SUM(CASE WHEN TO_CHAR(birthday + (INTERVAL '1' YEAR) * (LEVEL -1), 'FMD') IN ('1','7') THEN 1 END)
FROM b
CONNECT BY birthday + (INTERVAL '1' YEAR) * (LEVEL - 1) <= sysdate
Where TO_CHAR(...,'FMD') gives the day of the week from 1 = Sunday till 7 = Saturday

Counting the number of days excluding sunday between two dates

I am trying to calculate number of days betwen two dates excluding sundays. This is my query,
SELECT F_PLANHM_END_DT
- F_PLANHM_ST_DT
- 2
* (TO_CHAR (F_PLANHM_END_DT, 'WW') - TO_CHAR (F_PLANHM_ST_DT, 'WW'))
FROM VW_S_CURV_PROC
WHERE HEAD_MARK = 'IGG-BLH-BM 221';
SELECT COUNT (*)
FROM (SELECT SYSDATE + l trans_date
FROM ( SELECT LEVEL - 1 l
FROM VW_S_CURV_PROC
CONNECT BY LEVEL <= ( (SYSDATE + 7) - SYSDATE)))
WHERE TO_CHAR (trans_date, 'dy') NOT IN ('sun');
I am retrieving date from a view called VW_S_CURV_PROC with start date : F_PLANHM_ST_DT and end date F_PLANHM_END_DT. Somehow i cant make this to work. Please help me...
You could use the ROW GENERATOR technique to first generate the dates for a given range, and then exclude the SUNDAYs.
For example, this query will give me the total count of days between 1st Jan 2014 and 31st Dec 2014, excluding the Sundays -
SQL> WITH DATA AS
2 (SELECT to_date('01/01/2014', 'DD/MM/YYYY') date1,
3 to_date('31/12/2014', 'DD/MM/YYYY') date2
4 FROM dual
5 )
6 SELECT SUM(holiday) holiday_count
7 FROM
8 (SELECT
9 CASE
10 WHEN TO_CHAR(date1+LEVEL-1, 'DY','NLS_DATE_LANGUAGE=AMERICAN') <> 'SUN'
11 THEN 1
12 ELSE 0
13 END holiday
14 FROM data
15 CONNECT BY LEVEL <= date2-date1+1
16 )
17 /
HOLIDAY_COUNT
-------------
313
SQL>

oracle select data between date range using connect by clause

I have data something like this
date count
01-JAN-2015 10
02-JAN-2015 20
03-JAN-2015 30
01-FEB-2015 4
02-FEB-2015 8
03-FEB-2015 12
01-MAR-2015 5
02-MAR-2015 10
03-MAR-2015 15
01-APR-2015 6
02-APR-2015 12
03-APR-2015 18
01-MAY-2015 7
02-MAY-2015 14
03-MAY-2015 21
01-JUN-2015 8
02-JUN-2015 16
03-JUN-2015 24
01-JUL-2015 8
02-JUL-2015 16
03-JUL-2015 24
I need result group by months with variable number of months from current month
Example If I need only for next 2 months from today result is
MAR-2015 24
APR-2015 36
and If I need only for next 3 months from today result is
MAR-2015 24
APR-2015 36
MAY-2015 42
I have query to the get variable months with start date and end date of month
SELECT TO_CHAR(TRUNC(ADD_MONTHS(sysdate,level),'MM'),'MON-yyyy') MNTH ,
TO_CHAR(TRUNC(ADD_MONTHS(sysdate,level),'MM'),'dd-MON-yyyy') strt_date,
TO_CHAR(TRUNC(LAST_DAY(ADD_MONTHS(SYSDATE, level))),'dd-MON-yyyy') end_date
FROM dual
CONNECT BY LEVEL <= p_level
Where p_level is variable number of months like 2,3,4....
Can any 1 help using SQL query without using PL/SQL
You don't need to use a connect by clause at all.
select to_char(trunc(t.date, 'mm'), 'MON-YY')
, count(1)
from your_table_here t
where trunc(t.date, 'mm') > sysdate
and trunc(t.date, 'mm') < add_months(sysdate, :months)
group by trunc(t.date, 'mm')
Just insert the correct value for :months variable.

return zero when grouping by week after select -

I have some code below
select
'WEEK '|| row_number() over(order by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW')) WEEK,
count(*)
from opencall
where trunc(to_date(substr(LOGDATE,1,10), 'DD-MM-YY')) BETWEEN '01-JAN-14' AND '31-DEC-14'
group by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW')
order by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW');
Which is a great piece of code that another stackoverflow chap wrote for me for extracting calls from the database and counting / grouping them by week and it works perfectly if there are always calls in every week.
However I've tried reusing this code for other uses and if there is no result in a given week I get fewer groupings i.e. perhaps only 37 weeks returned instead of the current 50 weeks for instance.
As this is removing the weeks where there are no calls the week numbers dont equate to real week numbers in the year. So I don't actually know what weeks the calls are being returned from as the weeks remain sequential rather than having zeros in the weeks with no calls.
Is there any way to return a zero value if there are no results returned for a given week? I imagine that may make the code much more complex.
If I am using this code over a week
e.g:
WEEK 1 231
WEEK 2 657
WEEK 3 529
WEEK 4 606
WEEK 5 594
WEEK 6 517
WEEK 7 683
WEEK 8 664
WEEK 9 583
WEEK 10 740
If you want to know which week you are showing, then why the fuss with row_number()?
This gives you the year separated in weeks, starting with the first seven days make week 1 and so on:
select to_char(mydate, 'ww'), count(*)
from
(
select to_date(substr(logdate,1,10), 'dd-mm-yy') as mydate
from opencall
)
where extract(year from mydate) = 2014
group by to_char(mydate, 'ww')
order by to_char(mydate, 'ww');
(Why is LOGDATE a string? And why are its first 10 characters in the format 'DD-MM-YY' which is 8 characters long?)
select
'WEEK '|| row_number() over(order by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW')) WEEK,
row_number() over(order by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW')) mWeek,
count(*)
from (SELECT to_char(SYSDATE - (LEVEL * 7),'IW') TheDate
FROM dual
CONNECT BY LEVEL <= 52) WoY
LEFT JOIN opencall
on Woy.TheDate = OpenCall.mWeek
where trunc(to_date(substr(LOGDATE,1,10), 'DD-MM-YY')) BETWEEN '01-JAN-14' AND '31-DEC-14'
group by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW')
order by trunc(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'SATURDAY'), 'IW');
Something like this may work.
I tried something like this with test data and works. I hope this works for you too:
select
'WEEK '|| row_number() over(order by nvl(to_char(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY') ,'SATURDAY'), 'IW'),week)) WEEK
,count(wk)
from (select t.*,to_char(to_date(substr(LOGDATE,1,10), 'DD-MM-YY'),'IW') wk,w.week from
table1 t right join (SELECT lpad(level,2,0) week
FROM dual
CONNECT BY LEVEL <= 52 ) w on (to_char(to_date(substr(t.LOGDATE,1,10), 'DD-MM-YY'),'IW') = w.week)
order by w.week)
where trunc(to_date(substr(LOGDATE,1,10), 'DD-MM-YY')) BETWEEN '01-JAN-14' AND '31-DEC-14'
group by nvl(to_char(NEXT_DAY(to_date(substr(LOGDATE,1,10), 'DD-MM-YY') ,'SATURDAY'), 'IW'),week)
;
--Creating a test table under schema alber and inserting data on it for all days on weeks multiple of 4.
create table alber.week_table (mydate date, mydescription varchar2(100));
declare
cur_date date := to_date('01/01/'||to_char(sysdate,'yyyy'),'dd/mm/yyyy') ;
week number := 01;
begin
EXECUTE IMMEDIATE 'TRUNCATE TABLE alber.week_table';
while (cur_date < sysdate) loop
if mod(week,4) = 0 then
insert into alber.week_table values(cur_date, to_char(sysdate, 'day dd month yyyy hh24:mi:ss')) ;
end if;
cur_date := cur_date + 1;
week := to_number(to_char(cur_date,'IW'));
end loop;
end;
--Then one possible solution would be:
select theweek "Week", sum( decode( nvl(mydescription,0),'0',0,1) ) "Num of Records"
FROM
(
SELECT to_char(SYSDATE - (LEVEL * 7),'IW') theweek
FROM dual
CONNECT BY LEVEL <= 52
) w
LEFT JOIN week_table ON w.theweek = to_char(mydate,'IW')
group by theweek
order by 1;
Result
Week Num of Records
---- ----------------------
01 0
02 0
03 0
04 7
05 0
06 0
07 0
08 7
09 0
10 0
11 0
12 7
13 0
14 0
15 0
16 7
17 0
18 0
.
.
.