Calculate Every n record SQL - sql

I have the following table:
oDateTime oValue
------------------------------------
2017-09:30 23:00:00 8
2017-09-30 23:15:00 7
2017-09-30 23:30:00 7
2017-09-30 23:45:00 7
2017-10-01 00:00:00 6
2017-10-01 00:15:00 5
2017-10-01 00:30:00 8
2017-10-01 00:45:00 7
2017-10-01 01:00:00 6
2017-10-01 01:15:00 9
2017-10-01 01:30:00 5
2017-10-01 01:45:00 6
2017-10-01 02:00:00 7
The table will have one record every 15 minutes. I want to SUM or Average those records every 15 minutes.
So, the result should be:
oDateTime Sum_Value Avg_Value
---------------------------------------------------
2017-10-01 00:00:00 35 7
2017-10-01 01:00:00 32 6.4
2017-10-01 02:00:00 33 6.6
the SUM for 2017-10-01 00:00:00 is taken from 5 records before it and so on.
does anyone know how to achieve this?
Thank you.

Here is one method in SQL Server 2008:
select t.oDateTime, tt.sum_value, tt.avg_value
from (select oDateTime
from t
where datepart(minute, oDateTime) = 0
) t outer apply
(select sum(oValue) as sum_value, avg(oValue) as avg_Value
from (select top 5 t2.*
from t t2
where t2.oDateTime <= t.oDateTime
order by t2.oDateTime desc
) tt
) tt;
In more recent versions of SQL Server, you can use window functions for this purpose.

Just join the table to itself, and group by the master timestamp
This below is easily adjustable, to include how many minutes back you want. Handles change in frequency, i.e. doesn't assume 5 rows wanted, so if the data came in in 5 minutes intervals this is handled.
select cast('2017-09-30 23:00:00' as datetime) t,8 o
into #a
union all
select '2017-09-30 23:15:00',7 union all
select '2017-09-30 23:30:00',7 union all
select '2017-09-30 23:45:00',7 union all
select '2017-10-01 00:00:00',6 union all
select '2017-10-01 00:15:00',5 union all
select '2017-10-01 00:30:00',8 union all
select '2017-10-01 00:45:00',7 union all
select '2017-10-01 01:00:00',6 union all
select '2017-10-01 01:15:00',9 union all
select '2017-10-01 01:30:00',5 union all
select '2017-10-01 01:45:00',6 union all
select '2017-10-01 02:00:00',7
select x.t,sum(x2.o),avg(cast(x2.o as float))
from #a x, #a x2
where x2.t between dateadd(mi,-60,x.t) and x.t
group by x.t

Related

How to fill the time gap after grouping date record for months in postgres

I have table records as -
date n_count
2020-02-19 00:00:00 4
2020-07-14 00:00:00 1
2020-07-17 00:00:00 1
2020-07-30 00:00:00 2
2020-08-03 00:00:00 1
2020-08-04 00:00:00 2
2020-08-25 00:00:00 2
2020-09-23 00:00:00 2
2020-09-30 00:00:00 3
2020-10-01 00:00:00 11
2020-10-05 00:00:00 12
2020-10-19 00:00:00 1
2020-10-20 00:00:00 1
2020-10-22 00:00:00 1
2020-11-02 00:00:00 376
2020-11-04 00:00:00 72
2020-11-11 00:00:00 1
I want to be grouped all the records into months for finding month total count which is working, but there is a missing of month. how to fill this gap.
time month_count
"2020-02-01" 4
"2020-07-01" 4
"2020-08-01" 5
"2020-09-01" 5
"2020-10-01" 26
"2020-11-01" 449
This is what I have tried.
SELECT (date_trunc('month', date))::date AS time,
sum(n_count) as month_count
FROM table1
group by time
order by time asc
You can use generate_series() to generate all starts of months between the earliest and latest date available in the table, then bring the table with a left join:
select d.dt, coalesce(sum(t.n_count), 0) as month_count
from (
select generate_series(date_trunc('month', min(date)), date_trunc('month', max(date)), '1 month') as dt
from table1
) as d(dt)
left join table1 t on t.date >= d.dt and t.date < d.dt + interval '1 month'
group by d.dt
order by d.dt
I would simply UNION a date series, generated from MIN and MAX date:
demo:db<>fiddle
WITH cte AS ( -- 1
SELECT
*,
date_trunc('month', date)::date AS time
FROM
t
)
SELECT
time,
SUM(n_count) as month_count --3
FROM (
SELECT
time,
n_count
FROM cte
UNION
SELECT -- 2
generate_series(
(SELECT MIN(time) FROM cte),
(SELECT MAX(time) FROM cte),
interval '1 month'
)::date,
0
) s
GROUP BY time
ORDER BY time
Use CTE to calculate date_trunc only once. Could be left out if you like to call your table twice in the UNION below
Generate monthly date series from MIN to MAX date containing your n_count value = 0. Add it to the table
Do your calculation

Get List of Last 15 Days Date in SQL

Could SQL get list of date of last 15 days date in a single query?
We can get today date with
select current_date()
We also can get last 15 days date with
select date_add(current_date(), -15)
But how to show the list of last 15 days date?
For example the output is
2020-05-17,
2020-05-18,
2020-05-19,
2020-05-20,
2020-05-21,
2020-05-22,
2020-05-23,
2020-05-24,
2020-05-25,
2020-05-26,
2020-05-27,
2020-05-28,
2020-05-29,
2020-05-30,
2020-05-31
In Hive or Spark-SQL:
select date_add (date_add(current_date,-15),s.i) as dt
from ( select posexplode(split(space(15),' ')) as (i,x)) s
Result:
2020-05-18
2020-05-19
2020-05-20
2020-05-21
2020-05-22
2020-05-23
2020-05-24
2020-05-25
2020-05-26
2020-05-27
2020-05-28
2020-05-29
2020-05-30
2020-05-31
2020-06-01
2020-06-02
See also this answer.
WITH
cte AS ( SELECT 1 num UNION ALL SELECT 2 UNION ALL ... UNION ALL SELECT 15 )
SELECT DATEADD(CURRENT_DATE(), -num)
FROM cte;
Or, for example
WITH
cte1 AS ( SELECT 1 num UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 ),
cte2 AS ( SELECT 0 num
UNION ALL SELECT 1
UNION ALL SELECT 2 )
SELECT DATEADD(CURRENT_DATE(), -cte1.num - cte2.num * 5)
FROM cte1, cte2;

ORACLE SQL - How to find the number of reliefs each teacher has, each day, 2 months before the teacher resigned?

I need some help in finding the number of reliefs each teacher has, every single day, 2 months before the teacher resigns.
Join_dt - teacher's join date,
Resign_dt - teacher's resign date,
Relief_ID - Relief teacher's ID,
Start_dt - Relief's start date,
End_dt - Relief's end date,
note that there may be overlapping dates between 2 or more different reliefs and so I need to find the number of distinct reliefs each teacher has for each date.
This is what I am given:
Teacher_ID Join_dt Resign_dt Relief_ID Start_dt End_dt
12 2006-08-30 2019-08-01 20 2017-02-07 2019-07-04
12 2006-08-30 2019-08-01 20 2016-11-10 2019-01-30
12 2006-08-30 2019-08-01 103 2016-08-20 2019-07-29
12 2006-08-30 2019-08-01 17 2016-01-30 2017-12-30
23 2017-10-01 2018-11-12 44 2018-10-19 2018-11-11
23 2017-10-01 2018-11-12 29 2018-04-01 2018-12-02
23 2017-10-01 2018-11-12 06 2017-11-25 2018-05-02
05 2015-02-11 2019-10-02 38 2019-01-17 2019-07-21
05 2015-02-11 2019-10-02 11 2018-11-02 2019-02-05
05 2015-02-11 2019-10-02 15 2018-09-30 2018-10-03
Expected result:
Teacher_ID Dates No_of_reliefs
12 2019-07-31 0
12 2019-07-30 0
12 2019-07-29 1
12 2019-07-28 1
12 2019-07-27 1
... ...
12 2019-07-04 2
... ...
12 2016-05-30 2
12 2016-05-29 2
12 2016-05-28 2
12 2016-05-27 2
12 2016-05-26 1
23 2018-10-31 2
... ...
For date 2019-07-29, No_of_reliefs = 1 because of Relief_ID 103.
For date 2017-07-04, No_of_reliefs = 2 because of Relief_ID 20 & 103.
Dates are supposed to start from 1 month before the teacher resigned. For Teacher_ID 23, since she resigned on 2019-11-12, dates shall start from 2019-10-31.
I have tried using connect by but the execution time is really long since it involves a large amount of data.
Any other methods will be greatly appreciated!!
Thank you kind souls!!!
You can use
connect by level <= last_day(add_months(Resign_dt,-1)) - add_months(Resign_dt,-2) clause :
I suppose you mean 2 months before resignment for the starting date, and ending on the last day of the previous month.
with t1(Teacher_ID,Resign_dt,Relief_ID,start_dt,end_dt) as
(
select 12,date'2019-08-01',20 ,date'2017-02-07',date'2019-07-04' from dual union all
select 12,date'2019-08-01',20 ,date'2016-11-10',date'2019-01-30' from dual union all
select 12,date'2019-08-01',103,date'2016-08-20',date'2019-07-29' from dual
......
), t2 as
(
select distinct last_day(add_months(Resign_dt,-1)) - level + 1 as Resign_dt, Teacher_ID
from t1
connect by level <= last_day(add_months(Resign_dt,-1)) - add_months(Resign_dt,-2)
and prior Teacher_ID = Teacher_ID and prior sys_guid() is not null
)
select Teacher_ID, to_char(Resign_dt,'yyyy-mm-dd') as Dates,
(select count(distinct Relief_ID)
from t1
where t2.Resign_dt between start_dt and end_dt
and t2.Teacher_ID = Teacher_ID
)
from t2
order by Teacher_ID, Resign_dt desc;
Demo
select d.dt
, tr.Teacher_ID
--, tr.Join_dt
--, tr.Resign_dt
, count(tr.Relief_ID)
--, tr.Start_dt
--, tr.End_dt
from tr
right outer join (
SELECT dt
FROM (
SELECT DATE '2006-01-01' + ROWNUM - 1 dt
FROM DUAL CONNECT BY ROWNUM < 5000
) q
WHERE EXTRACT(YEAR FROM dt) < EXTRACT(YEAR FROM sysdate) + 2
--order by 1
) d on d.dt between tr.Join_dt and tr.End_dt
and d.dt between tr.Start_dt and tr.Resign_dt
group by d.dt
, tr.Teacher_ID
order by d.dt desc

bigquery - calculate monthly outstanding values

I'm trying to solve the following problem:
a user took three loans with running times of 3,4 and 5 months.
How to calculate in BigQuery for each point in time, how much he owns?
I know to do this calculation in R or Python but would clearly prefer a BigQuery/SQL solution.
Thank you!
I have the data:
Take Date Return Date Sum
2016-01-01 2016-03-31 10
2016-02-01 2016-05-31 20
2016-03-01 2016-07-31 50
I need the output like this:
Date Sum
2016-01-01 10
2016-02-01 30
2016-03-01 80
2016-04-01 70
2016-05-01 70
2016-06-01 50
2016-07-01 50
2016-08-01 0
Below is for BigQuery Standard SQL
#standardSQL
WITH `project.dataset.table` AS (
SELECT 1 id, DATE '2016-01-01' take_date, DATE '2016-03-31' return_date, 10 amount
UNION ALL SELECT 1, DATE '2016-02-01', DATE '2016-05-31', 20
UNION ALL SELECT 1, DATE '2016-03-01', DATE '2016-07-31', 50
), dates AS (
SELECT id, day
FROM (
SELECT id, GENERATE_DATE_ARRAY(
MIN(take_date),
DATE_ADD(DATE_TRUNC(MAX(return_date), MONTH), INTERVAL 1 MONTH),
INTERVAL 1 MONTH
) days
FROM `project.dataset.table`
GROUP BY id
), UNNEST(days) day
)
SELECT d.id, d.day, SUM(IF(d.day BETWEEN t.take_date AND t.return_date, amount, 0)) amount
FROM dates d
LEFT JOIN `project.dataset.table` t
ON d.id = t.id
GROUP BY d.id, d.day
ORDER BY d.day
with result as
Row id day amount
1 1 2016-01-01 10
2 1 2016-02-01 30
3 1 2016-03-01 80
4 1 2016-04-01 70
5 1 2016-05-01 70
6 1 2016-06-01 50
7 1 2016-07-01 50
8 1 2016-08-01 0

T-SQL to Group time interval change by date range in sql server

The original table has the column Timestamp with Interval
Interval: difference in minute between the current and previous Timestamp when sorted by Timestamp itself
Timestamp Interval(InMinute)
2016-12-31 00:28:00 NULL
2016-12-31 00:29:00 1
2016-12-31 00:30:00 1
2016-12-31 00:45:00 15
2016-12-31 01:00:00 15
2016-12-31 01:15:00 15
2016-12-31 01:16:00 1
2016-12-31 01:17:00 1
2016-12-31 01:18:00 1
2016-12-31 01:19:00 1
I want to detect a time interval change using T-SQL and produce the output
StartDate EndDate Interval
2016-12-31 00:28:00 2016-12-31 00:30:00 1
2016-12-31 00:30:00 2016-12-31 01:15:00 15
2016-12-31 01:15:00 2016-12-31 01:19:00 1
I wanted to tell for how long an Interval stayed the same. The second row says that from 2016-12-31 00:30:00 to 2016-12-31 01:15:00, the Interval stayed the same i.e. 15. But then it changed back to 1 after 2016-12-31 01:15:00
Try the below:
declare #tbl table
(datec datetime)
insert into #tbl
select '2016-12-31 00:29:00'
union all
select '2016-12-31 00:30:00'
union all
select '2016-12-31 00:45:00'
union all
select '2016-12-31 01:00:00'
union all
select '2016-12-31 01:01:00'
union all
select '2016-12-31 01:02:00'
select datec,nextdatec,datediff(MINUTE,datec,nextdatec) as diff from (
select datec,LEAD(datec) over(order by datec) as nextdatec from #tbl
) tbl
where datediff(MINUTE,datec,nextdatec) is not null
This will work
CREATE TABLE ##T1 (DATE_STAMP DATETIME)
INSERT INTO ##T1 VALUES ('12-31-2016 00:29:00')
INSERT INTO ##T1 VALUES ('12-31-2016 00:30:00')
INSERT INTO ##T1 VALUES ('12-31-2016 00:45:00')
INSERT INTO ##T1 VALUES ('12-31-2016 01:00:00')
INSERT INTO ##T1 VALUES ('12-31-2016 01:01:00')
INSERT INTO ##T1 VALUES ('12-31-2016 01:02:00')
SELECT ROW_NUMBER() OVER(ORDER BY DATE_STAMP) ID, * INTO ##T2 FROM ##T1
SELECT A.DATE_STAMP START_DATE
,B.DATE_STAMP END_DATE
,DATEDIFF(MINUTE, A.DATE_STAMP, B.DATE_STAMP) INTERVAL
FROM ##T2 A
INNER JOIN ##T2 B
ON B.ID = A.ID + 1
DROP TABLE ##T1, ##T2
Answered on Stackexchange
Fiddle Link