Counting the number of days excluding sunday between two dates - sql

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>

Related

Oracle - Get all days from month

How create select which return all days from month where month = PARAMETER_MONTH eg. 5 and year = extract(year from sysdate).
1
2
3
..
30
31
"Row generator" is the search keyword. For example:
SQL> with temp (col) as
2 (select to_date(&par_month, 'mm') from dual)
3 select to_number(to_char(col + level - 1, 'dd')) day
4 from temp
5 connect by level <= last_day(col) - col + 1
6 order by day;
Enter value for par_month: 5
DAY
----------
1
2
3
4
5
6
<snip>
29
30
31
31 rows selected.
SQL>
TO_DATE function will convert entered value into the 1st day of that month in current year, so you don't have to worry about "and year = extract(year from sysdate)" you mentioned in question.

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

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.

Getting Month values for specific year

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))

Oracle sql sort week days by current day

I am trying to sort the days based on the order: Saturday, Sunday, Monday, Tuesday, Wednesday, Thursday, Friday.
I am trying using case:
select day,
CASE day
WHEN 1 THEN 1
WHEN 2 THEN 2
WHEN 3 THEN 3
WHEN 4 THEN 4
WHEN 5 THEN 5
WHEN 6 THEN 6
WHEN 7 THEN 7
else 0
END as day_nr
from week where day in (1,2,3,4,5,6,7)
order by day_nr asc
This is ok when I select all the days of the week. But if I want only for the day 1,5,6 the ordering is not correct. Gets the first day -Monday. How to proceed?
If you're trying to sort a set of dates by day of the week, with Saturday being the first, then consider ordering by a modified date:
create table t1(my_date date);
insert into t1
select trunc(sysdate)+rownum
from dual
connect by level <= 20
select
my_date,
to_char(my_date,'Day'),
to_char(my_date,'D')
from
t1
order by
to_char(my_date + 1,'D');
http://sqlfiddle.com/#!4/5940b/3
The downside is that it's not very intuitive, so add a code comment if you use this method.
Edit: Where you have a list of numbers, order by a case statement with either a list conversion:
case day
when 1 then 3
when 2 then 4
when 3 then 5
when 4 then 6
when 5 then 7
when 6 then 1 -- saturday
when 7 then 2
end
... or the more compact, but not as intuitive:
case
when day <= 5 then day + 2
else day - 5
end
order by case
In Oracle day 1 is Sunday by default.
SELECT * FROM
(
SELECT trunc(sysdate) + LEVEL-1 my_dt
, TO_CHAR(trunc(sysdate) + LEVEL-1, 'DY') Wk_Day
, TO_CHAR(trunc(sysdate) + LEVEL-2, 'D' ) Day#
FROM dual
CONNECT BY LEVEL <= 10
)
WHERE Day# IN (1,5,6)
ORDER BY my_dt, Day#
/
MY_DT WK_DAY DAY#
------------------------
5/10/2013 FRI 5
5/11/2013 SAT 6
5/13/2013 MON 1
5/17/2013 FRI 5
5/18/2013 SAT 6