Query to get maximum value based on timestamp every 4 hour - sql

I have a sql table that stores data every 15 minutes, but I want to fetch the maximum value every 4 hour.
This is my Actual table:
+----+----+----+-------------------------+
| Id | F1 | F2 | timestamp |
+----+----+----+-------------------------+
| 1 | 24 | 30 | 2019-03-25 12:15:00.000 |
| 2 | 22 | 3 | 2019-03-25 12:30:00.000 |
| 3 | 2 | 4 | 2019-03-25 12:45:00.000 |
| 4 | 5 | 35 | 2019-03-25 13:00:00.000 |
| 5 | 18 | 23 | 2019-03-25 13:15:00.000 |
| ' | ' | ' | ' |
| 16 | 21 | 34 | 2019-03-25 16:00:00.000 |
+----+----+----+-------------------------+
The Output I am looking for is:
+----+----+----+
| Id | F1 | F2 |
+----+----+----+
| 1 | 24 | 35 |1st 4 Hours
+----+----+----+
| 2 | 35 | 25 |Next 4 Hours
+----+----+----+
I did use the query
select max(F1) as F1,
max(F2) as F2
from table
where timestamp>='2019/3/26 12:00:01'
and timestamp<='2019/3/26 16:00:01'
and it returns the first 4 hours value but when I Increase the timestamp from 4 hrs to 8 hrs it will still give me 1 max value rather than 2 per 4 hours.
I did try with the group by clause but wasn't able to get the expected result.

This should work
SELECT Max(f1),
Max(f2), datepart(hh,timestamp), convert(date,timestamp)
FROM TABLE
WHERE datepart(hh,timestamp)%4 = 0
AND timestamp>='2019/3/26 12:00:01'
AND timestamp<='2019/3/26 16:00:01'
GROUP BY datepart(hh,timestamp), convert(date,timestamp)
ORDER BY convert(date,timestamp) asc

Here is a relatively simple method:
select convert(date, timestamp) as dte,
(datepart(hour, timestamp) / 4) * 4 as hour,
max(F1) as F1,
max(F2) as F2
from table
group by convert(date, timestamp), (datepart(hour, timestamp) / 4) * 4;
This puts the date and hour into separate columns; you can use dateadd() to put them in one column.

Try this query:
declare #startingDatetime datetime = '2017-10-04 12:00:00';
select grp, max(F1) F1, max(F2) F2
from (
select datediff(hour, #startingDatetime, [timestamp]) / 4 grp, *
from MyTable
where [timestamp] > #startingDatetime
) a group by grp

Related

Is there a way to select records inserted in previous hour from the last recorded inserted record?

I have a table that looks like this that has quite a few records in it:
+---------+------+------------------------+
| unit | temp | login_time_utc |
+---------+------+------------------------+
| 1 | 53 | 2022-01-24 10:02:06 |
| 1 | 62 | 2022-01-24 10:10:01 |
| 2 | 34 | 2022-01-24 10:04:00 |
| 2 | 65 | 2022-01-24 16:08:59 |
| 2 | 65 | 2022-01-24 16:03:56 |
| 2 | 74 | 2022-01-24 16:06:53 |
| 3 | 74 | 2022-01-24 16:05:51 |
| 3 | 83 | 2022-01-24 17:09:49 |
| 3 | 73 | 2022-01-24 18:07:46 |
| 4 | 74 | 2022-01-24 18:11:43 |
+---------+------+------------------------+
I would like to select all the records for each unit that were inserted in the last hour from the most recently inserted record of that respective unit. Is that possible?
I can do this easily if its just the last hour from now, but I don't know how to do this if its the last hour of each units most recent insert.
I cannot use a loop or a cursor in this situation.
with cutoff as (
select unit, max(login_time_utc) as max_login
from T group by unit
)
select data.*
from cutoff cross apply (
select * from T t
where t.unit = cutoff.unit
and t.login_time_utc >= dateadd(hour, -1, cutoff.max_login)
) as data
You can use a window function and a CTE to identify the MAX date per unit. Then use DATEDIFF to find all the records in the last hour.
WITH cte AS (
SELECT *, MAX(login_time_utc) OVER (PARTITION BY unit) AS login_time_utc_max
FROM yourtable
)
SELECT unit, temp, login_time_utc
FROM cte
WHERE DATEDIFF(SS, login_time_utc, login_time_utc_max) <= 3600
ORDER BY login_time_utc

Grouping Data 3 Hours after the Initial Time

I need to be able to filter down a dataset to only show the first instance every 3 hours. If an instance is found, any other instances that occur up to 3 hours afterwards should be hidden.
The closes thing I've been able to find is using date_trunc to get the first instance each hour, but I need to hide specifically up to 3 hours after the first instance exactly.
Example Data:
+------------------------+-------+
| Timestamp | Value |
+------------------------+-------+
| "2015-12-29 13:35:00" | 65 |
| "2015-12-29 13:40:00" | 26 |
| "2015-12-29 13:45:00" | 80 |
| "2015-12-29 13:50:00" | 10 |
| "2015-12-29 16:40:00" | 76 |
| "2015-12-29 16:45:00" | 73 |
| "2016-01-04 08:05:00" | 87 |
| "2016-01-04 08:10:00" | 90 |
| "2016-01-04 08:15:00" | 52 |
| "2016-01-04 08:20:00" | 90 |
| "2016-01-04 08:25:00" | 23 |
| "2016-01-04 08:30:00" | 96 |
| "2016-01-04 13:35:00" | 53 |
| "2016-01-04 13:40:00" | 15 |
| "2016-01-04 13:45:00" | 85 |
+------------------------+-------+
Expected Result:
+------------------------+-------+
| Timestamp | Value |
+------------------------+-------+
| "2015-12-29 13:35:00" | 65 |
| "2015-12-29 16:40:00" | 76 |
| "2016-01-04 08:05:00" | 87 |
| "2016-01-04 13:30:00" | 7 |
+------------------------+-------+
Anyone have any ideas? Thank you so much for your help.
This is tricky, because you need to keep track of the last picked record to identify the next one - so you can't just group by 3 hours intervals.
Here is one approach using a recursive cte:
with recursive cte(ts, value) as (
select ts, value
from mytable
where ts = (select min(ts) from mytable)
union all
select x.*
from (select ts from cte order by ts desc limit 1) c
cross join lateral (
select t.ts, t.value
from mytable t
where t.ts >= c.ts + interval '3' hour
order by t.ts
limit 1
) x
)
select * from cte order by ts
The idea is to start from the earliest record in the table, then iterate by picking the first available record that is at least 3 hours later (this assumes no duplicates in the timestamp column).
Note that timestamp is not a good choice for a column name, because it conflicts with a language keyword (that's a datatype). I remaned it to ts in the query.
Demo on DB Fiddle:
ts | value
:------------------ | ----:
2015-12-29 13:35:00 | 65
2015-12-29 16:40:00 | 76
2016-01-04 08:05:00 | 87
2016-01-04 13:35:00 | 53

Query to get the count of data for particular customer with all other data from table

My table structure is as follows:
group_id | cust_id | ticket_num
------------------------------
60 | 12 | 1
60 | 12 | 2
60 | 12 | 3
60 | 12 | 4
60 | 30 | 5
60 | 30 | 6
60 | 31 | 7
60 | 31 | 8
65 | 02 | 1
I want to fetch all the data for group_id=60 and find the count of ticket_num for each customer in that group. My output should be like this:
cust_id | ticket_count | ticket_num
------------------------------
12 | 4 | 1
12 | | 2
12 | | 3
12 | | 4
30 | 2 | 5
30 | | 6
31 | 2 | 7
31 | | 8
I tried this query:
SELECT gd.cust_id, Count(gd.cust_id),gd.ticket_num
FROM Group_details gd
WHERE gd.group_id = 65
GROUP BY gd.cust_id;
But this query is not working.
You appear to want the ANSI/ISO standard row_number() functions and count() as a window function:
select gd.cust_id, count(*) over (partition by gd.cust_id) as num_tickets,
row_number() over (order by gd.cust_id) as ticket_seqnum
from group_details gd
where gd.group_id = 60;
use aggregate and subquery
select t2.*,t1.ticket_num from Group_details t1
inner join
(
SELECT gd.cust_id, Count(gd.ticket_num) as ticket_count
FROM Group_details gd where gd.group_id = 60
GROUP BY gd.cust_id
) t2 on t1.cust_id=t2.cust_id
http://sqlfiddle.com/#!9/dd718b/1

Showing date even zero value SQL

I have SQL Query:
SELECT Date, Hours, Counts FROM TRANSACTION_DATE
Example Output:
Date | Hours | Counts
----------------------------------
01-Feb-2018 | 20 | 5
03-Feb-2018 | 25 | 3
04-Feb-2018 | 22 | 3
05-Feb-2018 | 21 | 2
07-Feb-2018 | 28 | 1
10-Feb-2018 | 23 | 1
If you can see, there are days that missing because no data/empty, but I want the missing days to be shown and have a value of zero:
Date | Hours | Counts
----------------------------------
01-Feb-2018 | 20 | 5
02-Feb-2018 | 0 | 0
03-Feb-2018 | 25 | 3
04-Feb-2018 | 22 | 3
05-Feb-2018 | 21 | 2
06-Feb-2018 | 0 | 0
07-Feb-2018 | 28 | 1
08-Feb-2018 | 0 | 0
09-Feb-2018 | 0 | 0
10-Feb-2018 | 23 | 1
Thank you in advanced.
You need to generate a sequence of dates. If there are not too many, a recursive CTE is an easy method:
with dates as (
select min(date) as dte, max(date) as last_date
from transaction_date td
union all
select dateadd(day, 1, dte), last_date
from dates
where dte < last_date
)
select d.date, coalesce(td.hours, 0) as hours, coalesce(td.count, 0) as count
from dates d left join
transaction_date td
on d.dte = td.date;

Where clause changing the results of my datediff column, How can I work around this?

I'm trying to obtain the time elapsed while st1=5. Here is what I currently have, which gives me the datediff time for each state change. My issue is that when i add a where st1=5 clause the datediff shows the difference in time between instances where the state = 5 instead of time elapsed where state is 5.
select timestamp,st1,st2,st3,st4,
datediff(second, timestamp, lead(timestamp)
over (order by timestamp)) as timediff
from A6K_status
Order By Timestamp DESC
+-----+-----+-----+-----+---------------------+----------+
| st1 | st2 | st3 | st4 | TimeStamp | TimeDiff |
+-----+-----+-----+-----+---------------------+----------+
| 3 | 3 | 3 | 3 | 2018-07-23 07:51:06 | |
+-----+-----+-----+-----+---------------------+----------+
| 5 | 5 | 5 | 5 | 2018-07-23 07:50:00 | 66 |
+-----+-----+-----+-----+---------------------+----------+
| 0 | 0 | 10 | 10 | 2018-07-23 07:47:19 | 161 |
+-----+-----+-----+-----+---------------------+----------+
| 5 | 5 | 5 | 5 | 2018-07-23 07:39:07 | 492 |
+-----+-----+-----+-----+---------------------+----------+
| 3 | 3 | 10 | 10 | 2018-07-23 07:37:48 | 79 |
+-----+-----+-----+-----+---------------------+----------+
| 3 | 3 | 10 | 10 | 2018-07-23 07:37:16 | 32 |
+-----+-----+-----+-----+---------------------+----------+
I am trying to sum the time that the state of station1 is 5. From this table above(what I have right now) if i could just sum timediff Where st1=5 that would work perfectly. But by adding "where st1=5" to my query gives me the time difference between instances where the state = 5.
Any help would be much appreciated. I feel very close to the result I would like to achieve. Thanks you.
Edit
This is what I would like to achieve
+-----+------------+----------+
| st1 | TimeStamp | TimeDiff |
+-----+------------+----------+
| 5 | 2018-07-23 | 558 |
+-----+------------+----------+
You would use a subquery (or CTE):
select sum(timediff)
from (select timestamp, st1, st2, st3, st4,
datediff(second, timestamp, lead(timestamp) over (order by timestamp)) as timediff
from A6K_status
) s
where st1 = 5;
Assuming SQL Server, try something like this:
WITH SourceTable AS (
select TOP 100 PERCENT timestamp,st1,st2,st3,st4,
datediff(second, timestamp, lead(timestamp)
over (order by timestamp)) as timediff
from A6K_status
Order By Timestamp DESC
)
SELECT SUM(timediff) as totaltimediff
WHERE st1 = 5