get data in 'n' hours interval between two dates oracle - oracle

i am trying to get data between two dates in an 'n' hour intervals ... the problem is that i am not getting desired result after 8 hour intervals ... my value in 'n' interval can range up to any number between 1 to 120.
Following is the Pseudo code of what i am tying to do:
-- i first select number of hours between two dates
SELECT
24 * (SYSDATE - to_date('2018-04-16 15:20', 'YYYY-MM-DD hh24:mi')) AS diff_hours
FROM dual;
-- Then i use the above value in CONNECT BY ROWNUM <= ROUND((hours between two dates/n),0) to get data in n intervals
SELECT TRUNC(sysdate - (rownum/ROUND((24/n),0)),'HH24') as the_hour
FROM dual
CONNECT BY ROWNUM <= ROUND((hours between two dates/n),0) ;
Sample query
SELECT
24 * (SYSDATE - to_date('2018-04-16 15:20', 'YYYY-MM-DD hh24:mi')) AS diff_hours
FROM dual;
SELECT TRUNC(sysdate - (rownum/ROUND((24/8),0)),'HH24') as the_hour
FROM dual
CONNECT BY ROWNUM <= ROUND((724/8),0) ;
How can i change above query to get data in 'n' hour intervals between two dates, with n being any number of hours?

Remove the first ROUND() in your SELECT
SELECT TRUNC (SYSDATE - (ROWNUM / (24 / 9)), 'HH24') AS the_hour
FROM DUAL
CONNECT BY ROWNUM <= ROUND ( (724 / 9), 0);

try this,
SELECT TO_DATE(:p_date1, 'MM/DD/YYYY') + (FLOOR((rownum*:p_interval)/24) + (MOD((rownum*:p_interval), 24)/24)) dt
FROM DUAL
CONNECT BY (rownum*:p_interval) <= ((TO_DATE(:p_date2, 'MM/DD/YYYY')+.5) - TO_DATE(:p_date1, 'MM/DD/YYYY') + (MOD((rownum*:p_interval), 24)/24)) * 24
ORDER BY 1;

Related

How to get cout(*) based on sysdate -1

I want to get count(*) with table name printed with records which are sysdate-1 in oracle.
Select abc , count(*) from abc where dat_last_mnt < sysdate -1
With regards
Sree
In Oracle, a DATE is a binary data-type with 7 bytes for century, year-of-century, month, day, hour, minute and second and it ALWAYS has those 7 components.
If you want to find a count of the values that were yesterday then you need to filter to find the range of values between 00:00:00 and 23:59:59 on that day and you need to include a GROUP BY clause with all the columns you are not aggregating by:
SELECT column_name,
count(*)
FROM table_name
WHERE dat_last_mnt >= TRUNC(SYSDATE) - INTERVAL '1' DAY
AND dat_last_mnt < TRUNC(SYSDATE)
GROUP BY column_name;
Which, for the sample data:
CREATE TABLE table_name (column_name, dat_last_mnt) AS
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '2' DAY + INTERVAL '20' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '0' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '4' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '8' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '12' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '16' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '20' HOUR FROM DUAL UNION ALL
SELECT 'A', TRUNC(SYSDATE) - INTERVAL '0' DAY + INTERVAL '0' HOUR FROM DUAL UNION ALL
SELECT 'B', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '1' HOUR FROM DUAL UNION ALL
SELECT 'B', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '2' HOUR FROM DUAL UNION ALL
SELECT 'B', TRUNC(SYSDATE) - INTERVAL '1' DAY + INTERVAL '3' HOUR FROM DUAL UNION ALL
SELECT 'B', TRUNC(SYSDATE) - INTERVAL '0' DAY + INTERVAL '0' HOUR FROM DUAL;
Outputs:
COLUMN_NAME
COUNT(*)
A
6
B
3
db<>fiddle here

Just the month january not working

In this query I found the weeks of month, for example november begin 1th Wednesday and ends sunday 5.
These are the first week on november.
SELECT * FROM (
WITH days AS
(SELECT to_date('01012017','ddmmyyyy') + level-1 date_in
FROM dual
CONNECT BY level < 32)
SELECT date_in,
TO_CHAR(date_in,'IW') - TO_CHAR(TRUNC(date_in,'MM'),'IW') + 1 week_number
FROM days) where week_number = 1;
The week_number can change depending of the weeks of the month, but in January is not working.
Your requirement is not clear for me but perhaps you are looking for this:
SELECT TRUNC (next_day(TRUNC(TO_DATE('20022017','ddmmyyyy'), 'mm'),'monday') - 1), 'IW') AS first_week
FROM dual;
I'm still a bit unclear as to what you're looking for, but perhaps the following query will help you on your way:
WITH YEAR_START AS (SELECT TO_DATE('01012017', 'DDMMYYYY') AS FIRST_DAY_OF_YEAR
FROM DUAL),
MONTH_START AS (SELECT FIRST_DAY_OF_YEAR AS FIRST_DAY_OF_MONTH
FROM YEAR_START
UNION ALL
SELECT ADD_MONTHS(FIRST_DAY_OF_YEAR, LEVEL) AS FIRST_DAY_OF_MONTH
FROM YEAR_START
CONNECT BY LEVEL <= 11),
MONTH_START_AND_END AS (SELECT FIRST_DAY_OF_MONTH,
ADD_MONTHS(FIRST_DAY_OF_MONTH, 1) - INTERVAL '1' DAY AS LAST_DAY_OF_MONTH
FROM MONTH_START),
ABS_MONTH_WEEKS AS (SELECT FIRST_DAY_OF_MONTH,
LAST_DAY_OF_MONTH,
TO_NUMBER(TO_CHAR(FIRST_DAY_OF_MONTH, 'IW')) AS ABS_FIRST_WEEK_OF_MONTH,
TO_NUMBER(TO_CHAR(LAST_DAY_OF_MONTH, 'IW')) AS ABS_LAST_WEEK_OF_MONTH
FROM MONTH_START_AND_END),
REL_MONTH_WEEKS AS (SELECT a.*,
1 AS REL_FIRST_WEEK_OF_MONTH,
ABS_LAST_WEEK_OF_MONTH - CASE
WHEN ABS_FIRST_WEEK_OF_MONTH > ABS_LAST_WEEK_OF_MONTH THEN 0
ELSE ABS_FIRST_WEEK_OF_MONTH-1
END AS REL_LAST_WEEK_OF_MONTH
FROM ABS_MONTH_WEEKS a)
SELECT *
FROM REL_MONTH_WEEKS;
Best of luck.

Retrieve rows with 0 count from Oracle

I am woking on a query which can give back the count divided by month about the offices that will be closed this summer.
SELECT
qa.tmonth,
COUNT(qa.tmonth) AS qtn
FROM
(
SELECT TO_CHAR(CLOSURE_DATE, 'yyyymm') AS tmonth
FROM Holidays
WHERE CLOSURE_DATE >= TO_DATE('20160501', 'YYYY-MM-DD') AND
CLOSURE_DATE <= TO_DATE('20160901', 'YYYY-MM-DD')
) qa
GROUP BY qa.tmonth;
Since the months: May, June, August and September no office will be closed the output is the following:
TMONTH|QTN
201607|80
But I need a thing like this
TMONTH|QTN
201605|0
201606|0
201607|80
201608|0
201609|0
How could I achieve that?
Thanks to all!
You can try with something like this:
SQL> with holidays(closure_date) as
2 (
3 select date '2016-07-01' from dual union all
4 select date '2016-07-02' from dual union all
5 select date '2016-07-03' from dual union all
6 select date '2016-07-04' from dual union all
7 select date '2016-07-05' from dual
8 )
9 select count(closure_date) as closure_days, to_char(day, 'yyyymm') as month
10 from (
11 select date '2016-05-01' + level -1 as day
12 from dual
13 connect by date '2016-05-01' + level -1 <= date '2016-09-30'
14 ) days
15 left outer join holidays
16 on (day = closure_date)
17 group by to_char(day, 'yyyymm') ;
CLOSURE_DAYS MONTH
------------ ------
0 201608
5 201607
0 201606
0 201605
0 201609
SQL>
This uses a query to build the list of all the days between a starting and an ending date; I used 01/05 and 30/09 and called it days.
Then it queries days with the holidays table in outer join; this way you can count only the days for which there is a corrensponding value in the closure days list, thus counting the closure days for each day, month year; the aggregation for year and month completes the job
A similar approach like above. Tip: You can execute the two sub-queries separately, to analyse the logic.
select to_char (m.month, 'yyyymm') as TMONTH, m.month,
nvl (h.qtn, 0) as QTN
from
(
SELECT add_months(trunc (SYSDATE, 'MONTH'), -(LEVEL-1)) as MONTH
FROM dual
CONNECT BY LEVEL <= 12 -- generate a list of the last 12 month
) m
left join
(
SELECT trunc (closure_date, 'MONTH') as MONTH,
count (*) as QTN
FROM Holidays
group by trunc (closure_date, 'MONTH')
) h
on m.MONTH = h.MONTH
where m.month between DATE '2016-01-01' and sysdate
order by TMONTH desc;

weekly calender table in oracle to update alternative week flag & date

I'm creating a table to populate a weekly calendar table and my requirement is to update wk_start_date as every week sunday and populate the pr_wk_flag as Y every two weeks and
beg dt & end dt would be from two weeks before Thursday to current Wednesday
Like below, How to populate in oracle plsql
Wk_start_date pr_wk_flag beg dt end dt
2/9/2014 Y 1/30/2014 2/12/2014
2/16/2014 N NULL NULL
2/23/2014 Y 2/13/2014 2/26/2014
3/2/2014 N NULL NULL
3/9/2014 Y 2/27/2014 3/12/2014
Here's one way:
select wk_start_dt, pr_wk_flag,
case when pr_wk_flag = 'Y' then wk_start_dt - 10 end as beg_dt,
case when pr_wk_flag = 'Y' then wk_start_dt + 3 end as end_dt
from (
select next_day(date '2014-02-01' + (7 * level), 'SUN') as wk_start_dt,
decode(mod(level, 2), 1, 'Y', 'N') as pr_wk_flag
from dual
connect by level <= 6
);
The inner query is a common way to generate a sequence of values. Adjust the start date and the number of iterations to change the range of week-starts generated, and if necessary to flip the flag value. The SUN argument to the next_day function has to be in your local session language, so change that to something suitable if you're not using English. As a one-off insert I don't think the NLS-sensitivity is an issue in this case.
The outer query just uses the flag to decide whether to calculate the other two dates, or leave them null.
SQL Fiddle demo.
There you have for all 2014 year
SELECT dates+(8- to_char(TRUNC (TRUNC (dates, 'w'), 'YEAR'),'d')) wk_start_date,
DECODE (MOD (TO_NUMBER (TO_CHAR (dates, 'w')), 2), 0, 'Y', 'N')
pr_wk_flag,
DECODE (MOD (TO_NUMBER (TO_CHAR (dates, 'w')), 2),
0, dates + 5 - 17,
NULL)
pr_wk_flag,
DECODE (MOD (TO_NUMBER (TO_CHAR (dates, 'w')), 2), 0, dates + 3, NULL)
end_dt
FROM (SELECT TRUNC (SYSDATE, 'YEAR') + 7 * (ROWNUM - 1) dates
FROM dba_tables
WHERE TRUNC (TRUNC (SYSDATE, 'YEAR') + 7 * (ROWNUM - 1), 'YEAR') =
TRUNC (SYSDATE, 'YEAR'))
ORDER BY wk_start_date ASC

Finding a count of rows in an arbitrary date range using Oracle

The question I need to answer is this "What is the maximum number of page requests we have ever received in a 60 minute period?"
I have a table that looks similar to this:
date_page_requested date;
page varchar(80);
I'm looking for the MAX count of rows in any 60 minute timeslice.
I thought analytic functions might get me there but so far I'm drawing a blank.
I would love a pointer in the right direction.
You have some options in the answer that will work, here is one that uses Oracle's "Windowing Functions with Logical Offset" feature instead of joins or correlated subqueries.
First the test table:
Wrote file afiedt.buf
1 create table t pctfree 0 nologging as
2 select date '2011-09-15' + level / (24 * 4) as date_page_requested
3 from dual
4* connect by level <= (24 * 4)
SQL> /
Table created.
SQL> insert into t values (to_date('2011-09-15 11:11:11', 'YYYY-MM-DD HH24:Mi:SS'));
1 row created.
SQL> commit;
Commit complete.
T now contains a row every quarter hour for a day with one additional row at 11:11:11 AM. The query preceeds in three steps. Step 1 is to, for every row, get the number of rows that come within the next hour after the time of the row:
1 with x as (select date_page_requested
2 , count(*) over (order by date_page_requested
3 range between current row
4 and interval '1' hour following) as hour_count
5 from t)
Then assign the ordering by hour_count:
6 , y as (select date_page_requested
7 , hour_count
8 , row_number() over (order by hour_count desc, date_page_requested asc) as rn
9 from x)
And finally select the earliest row that has the greatest number of following rows.
10 select to_char(date_page_requested, 'YYYY-MM-DD HH24:Mi:SS')
11 , hour_count
12 from y
13* where rn = 1
If multiple 60 minute windows tie in hour count, the above will only give you the first window.
This should give you what you need, the first row returned should have
the hour with the highest number of pages.
select number_of_pages
,hour_requested
from (select to_char(date_page_requested,'dd/mm/yyyy hh') hour_requested
,count(*) number_of_pages
from pages
group by to_char(date_page_requested,'dd/mm/yyyy hh')) p
order by number_of_pages
How about something like this?
SELECT TOP 1
ranges.date_start,
COUNT(data.page) AS Tally
FROM (SELECT DISTINCT
date_page_requested AS date_start,
DATEADD(HOUR,1,date_page_requested) AS date_end
FROM #Table) ranges
JOIN #Table data
ON data.date_page_requested >= ranges.date_start
AND data.date_page_requested < ranges.date_end
GROUP BY ranges.date_start
ORDER BY Tally DESC
For PostgreSQL, I'd first probably write something like this for a "window" aligned on the minute. You don't need OLAP windowing functions for this.
select w.ts,
date_trunc('minute', w.ts) as hour_start,
date_trunc('minute', w.ts) + interval '1' hour as hour_end,
(select count(*)
from weblog
where ts between date_trunc('minute', w.ts) and
(date_trunc('minute', w.ts) + interval '1' hour) ) as num_pages
from weblog w
group by ts, hour_start, hour_end
order by num_pages desc
Oracle also has a trunc() function, but I'm not sure of the format. I'll either look it up in a minute, or leave to see a friend's burlesque show.
WITH ranges AS
( SELECT
date_page_requested AS StartDate,
date_page_requested + (1/24) AS EndDate,
ROWNUMBER() OVER(ORDER BY date_page_requested) AS RowNo
FROM
#Table
)
SELECT
a.StartDate AS StartDate,
MAX(b.RowNo) - a.RowNo + 1 AS Tally
FROM
ranges a
JOIN
ranges b
ON a.StartDate <= b.StartDate
AND b.StartDate < a.EndDate
GROUP BY a.StartDate
, a.RowNo
ORDER BY Tally DESC
or:
WITH ranges AS
( SELECT
date_page_requested AS StartDate,
date_page_requested + (1/24) AS EndDate,
ROWNUMBER() OVER(ORDER BY date_page_requested) AS RowNo
FROM
#Table
)
SELECT
a.StartDate AS StartDate,
( SELECT MIN(b.RowNo) - a.RowNo
FROM ranges b
WHERE b.StartDate > a.EndDate
) AS Tally
FROM
ranges a
ORDER BY Tally DESC

Resources