How to calculate sum of each group last row in mysql - mysql

vehicle_assignment_history
id companyAccountId date totalVan totalBike
1 4 2021-11-11 00:00:00 2 0
2 4 2021-11-11 00:00:00 3 0
3 4 2021-11-11 00:00:00 1 0
4 8 2021-11-11 00:00:00 1 0
5 8 2021-11-12 00:00:00 2 0
6 9 2021-11-13 00:00:00 0 2
7 9 2021-11-14 00:00:00 0 1
I want to calculate sum of each group last row of companyAccountId.also the date bewteen a range.
for example:-
2021-11-11 -> 2021-11-13
totalVan totalBike
1 + 2 + 0 = 3 0 + 0 + 2 = 2
2021-11-11 -> 2021-11-14
totalVan totalBike
1 + 2 + 0 = 3 0 + 0 + 1 = 1

One way to do this is to take the max (for each companyAccountId) of a complex string that joins the id and the field you want to find for the highest id, then extract the field you want from the end and convert it back to a number (all in a subquery, so you can sum all the resulting values)
select sum(latestTotalVan) as totalVan, sum(latestTotalBike) as totalBike
from (
select
cast(substring(max(concat(lpad(id,11,'0'),totalVan)) from 12) as unsigned) latestTotalVan,
cast(substring(max(concat(lpad(id,11,'0'),totalBike)) from 12) as unsigned) latestTotalBike
from vehicle_assignment_history
where date between '2021-11-11 00:00:00' and '2021-11-14 00:00:00'
group by companyAccountId
) latest_values
fiddle
mysql 8 adds window functions that make this kind of thing much easier.

SELECT
companyAccountId,
sum(totalVan) AS [Total Vans],
sum(totalBike) AS [Total Bike],
FROM vehicle_assignment_history
GROUP BY companyAccountId
HAVING '2021-11-11' < date AND date < '2021-11-13'

Related

how to group the data by some interval datetimes?

there are many devices and while using it will upload data every some seconds or minutes.
I want to get the sections of date-time that the device is in use
Id date-time value
0 2021-07-08 14:46:46 1
1 2021-07-08 14:47:47 5
2 2021-07-08 14:48:48 2
3 2021-07-08 14:49:49 4
4 2021-07-08 15:30:01 7
5 2021-07-08 15:30:46 4
6 2021-07-08 15:30:46 4
7 2021-07-08 15:50:04 4
8 2021-07-08 15:50:05 6
can it be true that group the data by an interval?
let us consider interval = 1 minutes
then group the data which the minus of the two date-time is more than 1 minutes.
then Id=0 or Id=1 or Id=2 or Id=3 is one group and Id=4 and Id=5 and Id=6 and Id=7 and Id=8 is another group
what I want is the group is a nearly date-time.
If the difference between two records is more than 1 minute then they are in two groups. If not they are in the same groups.
which means in the same group time1 will be smaller than 1 minutes to one of the other time.
If the time difference is 1 or 10 minutes larger than the previous record it will belong to a new groups
and I am using MYSQL
You can use lag window function to obtain previous date_time.
One way to calculate the time difference in seconds is to convert timestamp type to integer by unix_timestamp function.
Make a newgroup flag which equals one if and only if the difference from the previous record is larger than 60*10 seconds (10 minutes).
Cumulative sum of newgroup would become the section group ID.
with tmp AS (
SELECT
*,
coalesce(unix_timestamp(date_time) - unix_timestamp(lag(date_time) over (ORDER BY date_time)), 0) > 60*10 AS newgroup
FROM
tbl
)
,tmp2 AS (
SELECT
*,
sum(newgroup) over (ORDER BY date_time) AS groupid
FROM
tmp
)
SELECT * FROM tmp2
This query would get:
id date_time value newgroup groupid
0 2021-07-08 14:46:46 1 0 0
1 2021-07-08 14:47:47 5 0 0
2 2021-07-08 14:48:48 2 0 0
3 2021-07-08 14:49:49 4 0 0
4 2021-07-08 15:30:01 7 1 1
5 2021-07-08 15:30:46 4 0 1
6 2021-07-08 15:30:46 4 0 1
7 2021-07-08 15:50:04 4 1 2
8 2021-07-08 15:50:05 6 0 2
Hmmm . . . It sounds like you are looking for gaps to defines groups that are related, and the gaps are determined by the interval.
In pseudo-SQL, this might look like:
select min(date_time), max(date_time), count(*), avg(value)
from (select t.*,
sum(case when prev_date_time > date_time - interval '1 minute' then 0 else 1 end) over (order by date_time) as grp
from (select t.*,
lag(date_time) over (order by date_time) as prev_date_time
from t
) t
) t
group by grp;

Query within a query to obtain certain value with multiple joins in MySQL Select

I have 3 tables that I have joined in the MySQL query below. All works well EXCEPT I would like the timeadj value with a 1 in column countingtime
to show from table 'data', not the first timeadj value the query finds.
I know this needs to be a query within a query but I am going around in circles and getting no where.
SELECT ttt_entries.tttid, ttt_teams.teamname, data.RacersInTeam,
ttt_entries.CoffeeClass, SEC_TO_TIME(data.timeadj),
COUNT(IF(data.division=5,1,NULL)) 'A+',
COUNT(IF(data.division=10,1,NULL)) A,
COUNT(IF(data.division=20,1,NULL)) B,
COUNT(IF(data.division=30,1,NULL)) C,
COUNT(IF(data.division=40,1,NULL)) D
FROM ttt_entries
INNER JOIN ttt_teams
ON ttt_entries.tttid = ttt_teams.tttid
INNER JOIN (SELECT * FROM data ORDER BY data.countingtime DESC) as data
ON ttt_entries.tttid = data.teamid
WHERE ttt_entries.eventDate = DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE()) >4, -5, 2) + DAYOFWEEK(CURDATE())) * -1 DAY) -- last Thursday
AND data.wtrlid = '22'
GROUP BY ttt_teams.tttid
ORDER BY data.timeadj ASC
For example.... In Team 1 (data.teamid=1) there are 8 time values in timeadj. In the adjacent column (countingtime) is a value either 1 or 0 but only ever 1x 1 per team.
Table ttt_entries
ID tttid CoffeeClass
1 23 Mocha
2 52 Espresso
3 6 Frappe
Table ttt_teams
tttid Name
6 Team A
23 Team 1
52 Team 2
Table 'data'
id wtrlid teamid timeadj countingtime division
1 22 23 3467.123 0 10
2 22 23 3467.125 0 20
3 22 23 3467.432 0 10
4 22 23 3469.000 1 10
5 22 23 3469.112 0 10
6 22 23 3468.987 0 5
My code brings back
tttid teamname RacersInTeam CoffeeClass Time A+ A B C D
23 Team 1 6 Mocha 3467.123 1 4 1 0 0
I need it to bring back the same data but a different time:
tttid teamname RacersInTeam CoffeeClass Time A+ A B C D
23 Team 1 6 Mocha 3469.000 1 4 1 0 0
You can try below way -
SELECT ttt_entries.tttid, ttt_teams.teamname, data.RacersInTeam,
ttt_entries.CoffeeClass, SEC_TO_TIME(max(case when countingtime=1 then data.timeadj end)),
COUNT(IF(data.division=5,1,NULL)) 'A+',
COUNT(IF(data.division=10,1,NULL)) A,
COUNT(IF(data.division=20,1,NULL)) B,
COUNT(IF(data.division=30,1,NULL)) C,
COUNT(IF(data.division=40,1,NULL)) D
FROM ttt_entries
INNER JOIN ttt_teams
ON ttt_entries.tttid = ttt_teams.tttid
INNER JOIN (SELECT * FROM data ORDER BY data.countingtime DESC) as data
ON ttt_entries.tttid = data.teamid
WHERE ttt_entries.eventDate = DATE_ADD(CURDATE(), INTERVAL (IF(DAYOFWEEK(CURDATE()) >4, -5, 2) + DAYOFWEEK(CURDATE())) * -1 DAY) -- last Thursday
AND data.wtrlid = '22'
GROUP BY ttt_teams.tttid
ORDER BY data.timeadj ASC

MySQL - Calculate accumulation since reset event in a Table

This issue is a reference for my other question
Python solution has been done based on extract from MySQL DB (5.6.34) where original data are stored.
My question is: Is it possible to make such calculation straight in MySQL?
Just to remind:
There is 'runners' table with accumulated distance per runner and reset tags
runner startdate cum_distance reset_event
0 1 2017-04-01 100 1
1 1 2018-04-20 125 0
2 1 2018-05-25 130 1
3 2 2015-04-05 10 1
4 2 2015-10-20 20 1
5 2 2016-11-29 50 0
I would like to calculate an accumulated distance per runner since the reset point (my comments in brackets ()):
runner startdate cum_distance reset_event runner_dist_since_reset
0 1 2017-04-01 100 1 100 <-(no reset since begin)
1 1 2018-04-20 125 0 25 <-(125-100)
2 1 2018-05-25 130 1 30 <-(130-100)
3 2 2015-04-05 10 1 10 <-(no reset since begin)
4 2 2015-10-20 20 1 10 <-(20-10)
5 2 2016-11-29 50 0 30 <-(50-20)
So far I was able to calculate only differences between reset events:
SET #DistSinceReset=0;
SELECT
runner,
startdate,
reset_event,
IF(cum_distance - #DistSinceReset <0, cum_distance, cum_distance - #DistSinceReset) AS 'runner_dist_since_reset',
#DistSinceReset := cum_distance AS 'cum_distance'
FROM
runners
WHERE
reset_event = 1
GROUP BY runner, startdate
This answer is for MySQL 8.
The information you want is the most recent cum_distance for each user with reset_event = 1. You are using MySQL 8, so you can use window functions.
Here is one method:
select r.*,
(cum_distance - coalesce(preceding_reset_cum_distance, 0)) as runner_dist_since_reset
from (select r.*,
min(cum_distance) over (partition by runner order by preceding_reset) as preceding_reset_cum_distance
from (select r.*,
max(case when reset_event = 1 then start_date end) over
(partition by runner
order by start_date
rows between unbounded preceding and 1 preceding
) as preceding_reset
from runners r
) r
) r;

mysql join two table rows in one table

I have two tables e_sku and e_availability, In e_sku table i have 45 rows with the default availability as 1, below is an example
id is_available name
1 1 UN001N
2 1 UN002N
3 1 UN003N
4 1 UN004N
5 1 UN005N
6 1 UN006N
7 1 UN007N
8 1 UN008N
9 1 UN009N
10 1 UN010N
11 1 UN011N
12 1 UN012N
13 1 UN013N
14 1 UN014N
15 1 UN015N
16 1 UN016N
17 1 UN017N
18 1 UN018N
19 1 UN019N
20 1 UN020N
21 1 UN021N
22 1 UN022N
23 1 UN023N
24 1 UN024N
25 1 UN025N
26 1 UN026N
27 1 UN027N
28 1 UN028N
29 1 UN029N
30 1 UN030N
31 1 UN031N
32 1 UN032N
33 1 UN033N
34 1 UN034N
35 1 UN035N
36 1 UN036N
37 1 UN037N
38 1 UN038N
39 1 UN039N
40 1 UN040N
41 1 UN041N
42 1 UN042N
43 1 UN043N
44 1 UN044N
45 1 UN045N
Second table is e_availability in this table i am only storing the unavailability with dates below is the example
id e_sku_id is_available working_date
1 5 0 10/20/2016
2 8 0 10/20/2016
3 10 0 10/20/2016
4 1 0 10/20/2016
5 15 0 10/20/2016
6 11 0 10/19/2016
7 1 0 10/19/2016
Because the data is capturing every date for unavailability so i am only gathering the unavailable product's data in e_availability table w.r.t. dates, Now i am looking to show the data for each day as complete skus in such a way that every day report will show 45 skus and for available sku it will show 1 from e_sku table's column is_available and for unavailable sku it will show the column of is_availability from e_availability table
I am using mysql database, I tried many join queries but not getting the report.
can any one guide about which join i require
I got the result by using this query
SELECT * FROM (SELECT id,NAME,1 AS is_available FROM e_sku
WHERE company_id = 2
AND id NOT IN (SELECT id FROM (SELECT e_sku.id,e_sku.name, edge_availability.is_available FROM edge_availability
JOIN edge_working ON edge_working.`id` = edge_availability.`working_id`
JOIN e_sku ON e_sku.id = edge_availability.`sku_id`
WHERE edge_working.`working_date` = '2016-10-19' AND edge_availability.`store_id` = 84) X)
UNION
SELECT e_sku.id,e_sku.name, edge_availability.is_available FROM edge_availability
JOIN edge_working ON edge_working.`id` = edge_availability.`working_id`
JOIN e_sku ON e_sku.id = edge_availability.`sku_id`
WHERE edge_working.`working_date` = '2016-10-19' AND edge_availability.`store_id` = 84) Y
ORDER BY id
You can use a LEFT JOIN to detect when a date isn't found in the e_availability table. The join will return NULL for all the columns in that table, then you can default to the value from e_sku.
SELECT d.date, s.id, IFNULL(a.is_available, s.is_available) AS is_available
FROM all_dates AS d
CROSS JOIN e_sku AS s
LEFT JOIN e_availability ON d.working_date = a.date AND s.id = a.e_sku_id
You need to create an additional table all_dates that contains all the dates that you want to report on. See What is the most straightforward way to pad empty dates in sql results (on either mysql or perl end)? for how you can create such a table dynamically.

How to split column based on row value in mysql?

I need a column from row value.
I have two table.
Table 1 : working_day Contains list of all working day date.
date
--------
2013-03-30
2013-03-29
2013-03-28
Table 2 : entry contains each employee in and out time.
id In Out Date
1 9 0 2013-03-30
2 8 0 2013-03-30
3 7 0 2013-03-30
1 8 18 2013-03-29
2 9 16 2013-03-29
3 6 20 2013-03-29
4 12 15 2013-03-29
Expected Output :
ID 29-03-2013_IN 29-03-2013_Out 30-03-2013_In
1 8 18 9
2 9 16 8
3 6 20 7
4 12 15 0
Tried :
SELECT id,
Case condition1 for 29_in, // I don't know which condition suite here.
Case condition1 for 29_out,
Case condition1 for 30_in
FROM entry
WHERE DATE
IN (
SELECT *
FROM (
SELECT DATE
FROM working_day
ORDER BY DATE DESC
LIMIT 0 , 2
)a
)
You could try something like that:
select
e.id,
(SELECT `in` FROM entry WHERE id = e.id AND date = '2013-03-30') as '2013-03-30_in',
(SELECT `in` FROM entry WHERE id = e.id AND date = '2013-03-29') as '2013-03-29_in',
(SELECT `out` FROM entry WHERE id = e.id AND date = '2013-03-29') as '2013-03-29_out'
from entry e
group by e.id;
Here is Demo
IMO you should do this in application instead of SQL