Counted value grouped by date range - mysql

From a Call Detail Record (CDR) table, I need to compute the maximum channels that have been simultaneously busy in a specified time range. The table has one column for the end of the call time and another column for the call duration.
CallID DateTime Duration
1 2014-04-28 11:37:54 35
2 2014-04-28 11:37:53 82
3 2014-04-28 11:37:42 53
4 2014-04-28 11:37:37 159
5 2014-04-28 11:37:13 49
6 2014-04-28 11:37:02 267
7 2014-04-28 11:37:00 267
8 2014-04-28 11:36:54 49
9 2014-04-28 11:36:20 266
I would need a report for getting a response like this (time range in hours for example):
DateRange NumBusyChannels
2014-04-28 11:00-12:00 9
2014-04-28 10:00-11:00 5
EDIT: Sample table to test Miky response.
CallID DateTime Duration
014 2013-07-23 08:42:42 3
015 2013-07-23 08:42:42 3
019 2013-07-23 08:42:42 3
012 2013-07-23 08:10:00 3
013 2013-07-23 08:10:00 3
016 2013-07-23 08:10:00 3
017 2013-07-23 08:10:00 3
018 2013-07-23 08:10:00 3

You might start with a query like this which should give you the number of overlapping calls for each call.
SELECT COuter.*,
COALESCE(COverlap.Cnt,0) as NumChannelsInUse
FROM Cdr COuter
LEFT OUTER JOIN(
SELECT C1.CallId,
COUNT(*) as Cnt
FROM Cdr C1
INNER JOIN Cdr C2
ON (C2.DateTime >= C1.DateTime
AND
C2.DateTime <= DATE_ADD(C1.DateTime, INTERVAL C1.Duration SECOND))
OR
(DATE_ADD(C2.DateTime, INTERVAL C2.Duration SECOND) >= C1.DateTime
AND
DATE_ADD(C2.DateTime, INTERVAL C2.Duration SECOND) <= DATE_ADD(C1.DateTime, INTERVAL C1.Duration SECOND))
OR
(C1.DateTime >= C2.DateTime
AND
C1.DateTime <= DATE_ADD(C2.DateTime, INTERVAL C2.Duration SECOND) )
OR
(DATE_ADD(C1.DateTime, INTERVAL C1.Duration SECOND) >= C2.DateTime
AND
DATE_ADD(C1.DateTime, INTERVAL C1.Duration SECOND) < DATE_ADD(C2.DateTime, INTERVAL C2.Duration SECOND))
GROUP BY C1.CallId) COverlap
ON COuter.CallId = COverlap.CallId
You would then have to further manipulate the query to partition the results by hour and then to select the maximum for each hour..

Related

How to Sum week hours in MYSQL Table?

I have these rows in my Database Table.
ID Name Date working_hours
29 A 2020-04-07 14.45
29 A 2020-04-08 10.30
29 A 2020-04-06 06.30
29 A 2020-04-10 10.15
30 B 2020-04-09 09.15
30 B 2020-04-07 09.00
30 B 2020-04-08 09.00
30 B 2020-04-10 04.45
30 B 2020-04-06 07.45
30 B 2020-04-10 04.45
When I execute below Query
SELECT ID,Name, date, working_hours,sum(working_hours) as 'total_week_hours'
from tblstafftasks
WHERE date between
date_add('2020-04-10', interval -WEEKDAY('2020-04-10') day) and
date_add(date_add('2020-04-10', interval -WEEKDAY('2020-04-10')-1 day), interval 6 day)
group by ID
I Get below OUTPUT
ID Name Date working_hours total_week_hours
29 A 2020-04-10 10.15 41.2
30 B 2020-04-10 04.45 43.5
But I want output to look like below
ID Name Date working_hours total_week_hours
29 A 2020-04-07 14.45 41.2
29 A 2020-04-08 10.30 41.2
29 A 2020-04-06 06.30 41.2
29 A 2020-04-10 10.15 41.2
30 B 2020-04-09 09.15 43.5
30 B 2020-04-07 09.00 43.5
30 B 2020-04-08 09.00 43.5
30 B 2020-04-10 04.45 43.5
30 B 2020-04-06 07.45 43.5
30 B 2020-04-10 04.45 43.5
Any help will be highly appreciated.
Join the original table with a subquery that gets the weekly totals.
SELECT t1.ID, t1.Name, t1.date, t1.working_hours, t2.total_week_hours
FROM tblstafftasks AS t1
JOIN (
SELECT ID, SUM(working_hours) AS total_week_hours
WHERE date between
date_add('2020-04-10', interval -WEEKDAY('2020-04-10') day) and
date_add(date_add('2020-04-10', interval -WEEKDAY('2020-04-10')-1 day), interval 6 day
GROUP BY ID)
) AS t2 ON t1.ID = t2.ID
WHERE t1.date between
date_add('2020-04-10', interval -WEEKDAY('2020-04-10') day) and
date_add(date_add('2020-04-10', interval -WEEKDAY('2020-04-10')-1 day), interval 6 day)

MariaDb/MySQL sliding sum over 24 hours

My table have fields that represent starting and ending working period as datetime.
I need to find related entries that match a total of 14hours min over a sliding period of 24 hours.
I think window function will (maybe) save me, but MariadDB (i use) doesn't implement yet Range time intervals in window function.
here is some example data:
id starting_hour ending_hour
-- ------------------- -------------------
1 2018-09-02 06:00:00 2018-09-02 08:30:00
2 2018-09-03 08:30:00 2018-09-03 10:00:00
4 2018-09-03 11:00:00 2018-09-03 15:00:00
5 2018-09-02 15:30:00 2018-09-02 16:00:00
6 2018-09-02 16:15:00 2018-09-02 17:00:00
7 2018-09-20 00:00:00 2018-09-20 08:00:00
8 2018-09-19 10:00:00 2018-09-19 12:00:00
9 2018-09-19 12:00:00 2018-09-19 16:00:00
10 2018-10-08 12:00:00 2018-10-08 14:00:00
11 2018-10-29 09:00:00 2018-10-29 10:00:00
So how to find rows where in a 24 hours window their sum a more or equal to 14 hours.
thanks
Edit:
SELECT
id,
starting_hour,
ending_hour,
TIMEDIFF (ending_hour, starting_hour) AS duree,
(
SELECT SUM(TIMEDIFF(LEAST(ending_hour, DATE_ADD(a.starting_hour, INTERVAL 24 HOUR)), starting_hour)) / 10000
FROM `table` b
WHERE b.starting_hour BETWEEN a.starting_hour AND DATE_ADD(a.starting_hour, INTERVAL 24 HOUR)
) AS duration
FROM
`table` a
HAVING duration >= 14
ORDER BY starting_hour ASC
;
This returns Id 8 but i want the whole period. (eg: Id 8, Id 9 and Id 7)
EDIT2:
The expected results are ranges of working time where they are in a window of 24 hours and where their sum are more or equal to 14 hours.
EDIT 3:
In fact under MySQL 8 this seems to work.
SELECT * FROM (
SELECT
*,
SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(hs.`ending_hour`, hs.`starting_hour`))) OVER (ORDER BY hs.starting_hour RANGE BETWEEN INTERVAL '12' HOUR PRECEDING AND INTERVAL '12' HOUR following)) AS tot
FROM
table hs
WHERE hs.`starting_hour` > DATE_SUB(NOW(), INTERVAL 50 DAY) AND hs.`ending_hour` <= NOW()
ORDER BY hs.`starting_hour` ASC
) t1
HAVING tot >= '14:00:00'
;
Is there a way to do it under MariaDB 10.2 without window function ? Or without window range function ?

MYSQL group by month but not on first day of month

My table votes contains votes that have been made by users at different times:
id item_id position user_id created_at
1 2 0 1 11/21/2013 11:27
26 1 1 1 11/21/2013 11:27
27 3 2 1 11/21/2013 11:27
42 2 2 1 12/7/2013 2:20
41 3 1 1 12/7/2013 2:20
40 1 0 1 12/7/2013 2:20
67 2 2 1 12/13/2013 1:13
68 1 1 1 12/13/2013 1:13
69 3 0 1 12/13/2013 1:13
84 2 0 1 12/28/2013 2:29
83 3 2 1 12/28/2013 2:29
82 1 1 1 12/28/2013 2:29
113 3 0 1 1/17/2014 22:08
114 1 1 1 1/17/2014 22:08
115 2 2 1 1/17/2014 22:08
138 2 0 1 1/20/2014 16:49
139 1 1 1 1/20/2014 16:49
140 3 2 1 1/20/2014 16:49
141 1 1 11 1/20/2014 16:51
142 3 2 11 1/20/2014 16:51
143 2 0 11 1/20/2014 16:51
I need to tally the results on a monthly basis but here's the tricky part: the start/end of the month does not necessarily fall on the first day of the month. So if the votes are due on the 10th day of every month, I need a vote that was cast on the 10th to be in a different group from a vote that was cast on the 11th. Using the data above, I want to get three groups:
Group 1: 6 votes (11/21 and 12/7)
Group 2: 6 votes (12/13, 12/28)
Group 3: 9 votes (1/17, 1/20)
I've tried a lot of approaches but to no avail. This is my query right now:
select created_at, ADDDATE(DATE_FORMAT(created_at, '%Y-%m-01'),interval 10 day) as duedate,count("id") from votes where list_id = 2 group by duedate
I am getting group sizes of 3, 9, and 9, not 6, 6 and 9. Any help you can provide would be much appreciated. Thanks.
Your query is close. You just need to subtract 9 days (10 - 1) from the current day to get the month:
select created_at, date_sub(created_at, interval 9 day) as duedate,
count(id)
from votes
where list_id = 2
group by duedate;
date_format() converts a date to a string. There is no need to convert a date value to a character value for this query.
EDIT:
To group by month:
select date_format(date_sub(created_at, interval 9 day), '%Y-%m') as YYYYMM,
count(id)
from votes
where list_id = 2
group by YYYYMM;

MySQL Order By 2 colums (date/frequency)

I have a favorite table with 4 columns
employee_id
product_id
frequency
last_consumed_date
Now i'm getting the 6 rows with the highest frequency for the employee_id with a minimal frequency of 6.
Example with employee_id 1
SELECT * FROM `favorites`
WHERE `employee_id` = 1
AND `frequency` >= 6
ORDER BY `frequency` DESC LIMIT 0,6
So far so good!
But now i want to prefer the rows if the last_consumed_date is within a month (30 days), So i must do something with:
DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= `lastchanged`
Here is a table example to make it more clear
Table filled:
1 5 11 2012-10- 3
1 13 8 2012-11- 7
1 18 20 2012- 9-25
1 42 10 2012-11- 3
1 28 15 2012-10-17
1 9 7 2012-10- 8
1 64 9 2012-11- 1
2 24 8 2012- 8-28
2 12 5 2012-10-16
2 5 12 2012-11-11
Today is 2012-11- 8
30 days back is 2012-10- 9
Table returned after SQL:
1 28 15 2012-10-17 <Sorted by 30 days interval and frequency>
1 42 10 2012-11- 3
1 64 9 2012-11- 1
1 13 8 2012-11- 7
1 18 20 2012- 9-25 <Sorted by frequency>
1 5 11 2012-10- 3
Now the question is, How do i order those 2 things in 1 query?
First an order by the date (with 30 days interval)
and than an order by the frequency of seperated results (inside interval and all others)
Ohh i think i found my answer by trial-error ^v^
SELECT * FROM `favorites`
WHERE `employee_id` = 1
AND `frequency` >= 6
ORDER BY (DATE_SUB(CURDATE(),INTERVAL 30 DAY) <= `lastchanged`) DESC,
`frequency` DESC
LIMIT 0,6
For those who tried helping! Thank you

mySQL AVG a field with a range of dates on the same table

I have a table
date d_id r_id p_id q_sold onhand
2012-10-10 5 1 3025 3 10
2012-10-10 5 1 3022 12 20
2012-10-10 5 1 3023 15 33
2012-10-11 5 1 3025 3 10
2012-10-11 5 1 3022 12 20
2012-10-11 5 1 3023 15 33
2012-10-12 5 1 3025 3 10
2012-10-12 5 1 3022 12 20
2012-10-12 5 1 3023 15 33
2012-10-13 5 1 3025 3 10
2012-10-13 5 1 3022 12 20
2012-10-13 5 1 3023 15 33
2012-10-14 5 1 3025 3 10
2012-10-14 5 1 3022 12 10
2012-10-14 5 1 3023 15 33
2012-10-15 5 1 3025 3 5
2012-10-15 5 1 3022 12 5
2012-10-15 5 1 3023 15 33
I would like to get the result of the q_sold divided by average of the onhand over a 5 day period, while displaying the other data for a specific date like the 2012-10-15.
I create a query
set #stdate = '2012-10-10';
set #endate = '2012-10-15';
SELECT date, d_id,r_id,p_id,q_sold,onhand,qty_sold/AVG(qty_onhand)
FROM stp_vwsales_info_tots
WHERE date BETWEEN #stdate and #endate and d_id=5
GROUP BY d_id,r_id,p_id
But the result being showed is incorrect, it displays the data for the 2012-10-10 instead of 2010-10-15
date d_id r_id p_id q_sold onhand avg
2012-10-10 5 1 3022 12 20 0.7579
2012-10-10 5 1 3023 15 33 0.4545
2012-10-10 5 1 3025 3 10 0.3273
Can anyone help?
Use your #stdate and #endate as DATE(#stdate/#endate) or DATE_FORMAT(#stdate/#endate,'%Y-%m-%d') otherwise you have to convert #stdate/#endate from string to date through MySQL
i think what your looking for is something called a simple moving average.
to calculate this you'll need to use an inline subquery - so performance won't be the best.
assuming you want to calculate the average over the previous 5 day period, try something like this:
SELECT
date, d_id, r_id, p_id, q_sold, onhand,
( SELECT q_sold/AVG(t2.onhand)
FROM stp_vwsales_info_tots AS t2
WHERE p_id=t1.p_id AND DATEDIFF(t1.date, t2.date) BETWEEN 0 AND 4
) AS 'moving_avg'
FROM stp_vwsales_info_tots AS t1
GROUP BY t1.p_id,t1.date
order by t1.date;