Calculating datetime difference from separate rows and add them to get total - mysql

Click link below to see image.
I need to get the time diff highlighted in red and the time diff in blue. Then add the time together to get the total.
Below is the query that will show all the records.
The first 2 records i will need to get the time difference, which will be around 3 days 4 hours and the last 2 records should only be 2 mins. So in total it should be AROUND 3 days 4 hours and 2 mins.
query image
select so
, createDate
, o
, n
from userTrans
where ( n = 10 OR o = 10 ) and so = 'g220'
Below will show that i grouped the records to get the total time. This is not what i want because it is getting the min and max time diff. The result turns out to be 32 hours.
select so
, min(createDate) minDate
, max(createDate) maxDate
, TIMESTAMPDIFF(MINUTE, min(createDate), max(createDate)) diff
, CONCAT(
FLOOR(HOUR(TIMEDIFF(min(createDate), max(createDate))) / 24), ' days ',
MOD(HOUR(TIMEDIFF(min(createDate), max(createDate))), 24), ' hours ',
MINUTE(TIMEDIFF(min(createDate), max(createDate))), ' minutes') diff1
, count(*) hits
from userTrans
where ( n = 10 OR o = 10 ) and so = 'g220'
group by so
order by TIMESTAMPDIFF(MINUTE, min(createDate), max(createDate)) DESC
Will this be possible to achieve? I hope I was clear.
Thank you

You can use a correlated subquery to align the 2 date/time references for a calculation.
SELECT
*
, TIME_TO_SEC(TIMEDIFF(createDate,nextcreatedate))
FROM (
SELECT
so
, createDate
, (
SELECT
createDate
FROM table1 AS t2
WHERE t2.so = t1.so
AND t2.createDate > t1.createDate
ORDER BY
CreaDate
LIMIT 1
)
AS nextcreatedate
, n
, test
FROM table1 AS t1
WHERE o = 0
) d
In other dbms systems using lead() might provide a more convenient of getting the next needed createdate value.

Related

MySql - Selecting MAX & MIN and returning the corresponding rows

I trying to get the last 6 months of the min and max of prices in my table and display them as a group by months. My query is not returning the corresponding rows values, such as the date time for when the max price was or min..
I want to select the min & max prices and the date time they both occurred and the rest of the data for that row...
(the reason why i have concat for report_term, as i need to print this with the dataset when displaying results. e.g. February 2018 -> ...., January 2018 -> ...)
SELECT metal_price_id, CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term, max(metal_price) as highest_gold_price, metal_price_datetime FROM metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
ORDER BY metal_price_datetime DESC
I have made an example, extract from my DB:
http://sqlfiddle.com/#!9/617bcb2/4/0
My desired result would be to see the min and max prices grouped by month, date of min, date of max.. and all in the last 6 months.
thanks
UPDATE.
The below code works, but it returns back rows from beyond the 180 days specified. I have just checked, and it is because it joining by the price which may be duplicated a number of times during the years.... see: http://sqlfiddle.com/#!9/5f501b/1
You could use twice inner join on the subselect for min and max
select a.metal_price_datetime
, t1.highest_gold_price
, t1.report_term
, t2.lowest_gold_price
,t2.metal_price_datetime
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, max(metal_price) as highest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t1 on t1.highest_gold_price = a.metal_price
inner join (
select a.metal_price_datetime
, t.lowest_gold_price
, t.report_term
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, min(metal_price) as lowest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t on t.lowest_gold_price = a.metal_price
) t2 on t2.report_term = t1.report_term
simplified version of what you should do so you can learn the working process.
You need calculate the min() max() of the periods you need. That is your first brick on this building.
you have tableA, you calculate min() lets call it R1
SELECT group_field, min() as min_value
FROM TableA
GROUP BY group_field
same for max() call it R2
SELECT group_field, max() as max_value
FROM TableA
GROUP BY group_field
Now you need to bring all the data from original fields so you join each result with your original table
We call those T1 and T2:
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R1
ON tableA.group_field = R1.group_field
AND tableA.value = R1.min_value
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R2
ON tableA.group_field = R2.group_field
AND tableA.value = R2.max_value
Now we join T1 and T2.
SELECT *
FROM ( .... ) as T1
JOIN ( .... ) as T2
ON t1.group_field = t2.group_field
So the idea is if you can do a brick, you do the next one. Then you also can add filters like last 6 months or something else you need.
In this case the group_field is the CONCAT() value

Select multiple columns by date, count occurrence for each column

I am trying to get this query...
SELECT `Num_1`, COUNT(`Num_1`) AS `value_occurrence` FROM numbers WHERE MONTH(`Dates`) = 1 AND YEAR(`Dates`) = 1995 GROUP BY `Num_1` ORDER BY `value_occurrence` DESC
But for multiple columns as in 'Num_1', 'Num_2', 'Num_3', 'Num_4', 'Num_5' and return with the occurrence of each column such as 'num_1_occurrence', 'num_2_occurrence', 'num_3_occurrence', 'num_4_occurrence', 'num_5_occurrence' and all within the date specified.
numbers table
Example output
I had tried using...
SELECT `Num_1`,`Num_2`, `Num_3`,`Num_4`,`Num_5`,COUNT(`Num_1`,`Num_2`,`Num_3`,`Num_4`,`Num_5`) AS `num_1_occurrence`,`num_2_occurrence`,`num_3_occurrence`, `num_4_occurrence`,`num_5_occurrence`FROM numbers WHERE MONTH(`Dates`) = 1 AND YEAR(`Dates`) = 1995
but just threw errors, I have searched extensively for days and have not found the correct way to do it.
I'd do it like this:
SELECT n.num
, MAX(IF(n.q='n1',n.cnt,NULL)) AS num_1_occurrence
, MAX(IF(n.q='n2',n.cnt,NULL)) AS num_2_occurrence
, MAX(IF(n.q='n3',n.cnt,NULL)) AS num_3_occurrence
FROM (
SELECT 'n1' AS q
, n1.Num_1 AS num
, COUNT(n1.Num_1) AS cnt
FROM numbers n1
WHERE n1.Dates >= '1995-01-01'
AND n1.Dates < '1995-01-01' + INTERVAL 1 MONTH
GROUP BY n1.Num_1
UNION ALL
SELECT 'n2' AS q
, n2.Num_2 AS num
, COUNT(n2.Num_2) AS cnt
FROM numbers n2
WHERE n2.Dates >= '1995-01-01'
AND n2.Dates < '1995-01-01' + INTERVAL 1 MONTH
GROUP BY n2.Num_2
UNION ALL
SELECT 'n3' AS q
, n3.Num_3 AS num
, COUNT(n3.Num_3) AS cnt
FROM numbers n3
WHERE n3.Dates >= '1995-01-01'
AND n3.Dates < '1995-01-01' + INTERVAL 1 MONTH
GROUP BY n3.Num_3
) n
GROUP BY n.num
ORDER BY GREATEST(num_1_occurrence,num_2_occurrence,num_3_occurrence) DESC
I'm only doing Num_1 and Num_2 here, but I think it's what you're looking for, or close. This will give you the list in "tall" format, with the original column name, the value in that column, and the count of that value in that column going across...
SELECT 'Num_1' AS field_name, Num_1 AS value, value_count
FROM (SELECT Num_1, COUNT(Num_1) AS value_count
FROM numbers
GROUP BY Num_1) AS num1_counts
WHERE MONTH(`Dates`) = 1 AND YEAR(`Dates`) = 1995
UNION
SELECT 'Num_2' AS field_name, Num_2 AS value, value_count
FROM (SELECT Num_2, COUNT(Num_2) AS value_count
FROM numbers
GROUP BY Num_2) AS num2_counts
WHERE MONTH(`Dates`) = 1 AND YEAR(`Dates`) = 1995

Getting incorrect value from SQL Math Operation?

I am performing an operation to work out a percentage based on 2 values.
I have a single table that tracks an overall value against months and years.
Table Name - donation_tracker
I am comparing across all months across current and previous year then performing a calculation such as:
Current Value (Month- January, Year- 2014, CityID- 1) / Previous Value (Month- January, Year- 2013, CityID- 1) = Division Value * 100 = New Percentage Value.
Some of the math operations appear to be correct but some are incorrect for example the image below is showing 140 when it should be 130.
The values I am quering are as follows:
The column donation_amount is set as
Type = Decimal
Length = 10,2.
Sum should be 130...
SQL CODE-
SELECT city_markers.City_ID, city_markers.City_Name, city_markers.City_Lng, city_markers.City_Lat, SUM( d2.Donation_Amount ) , d1.Month, d1.Year, round( (
D2.Donation_amount / D1.Donation_amount
) *100, 2 )
FROM `city_markers`
INNER JOIN donation_tracker d1 ON city_markers.City_ID = d1.City_ID
INNER JOIN donation_tracker D2 ON d1.month = D2.month
AND d1.month = 'January'
AND d2.month = 'January'
AND d2.year = '2014'
AND D1.year = D2.year -1
AND D1.Location_ID = D2.Location_ID
GROUP BY city_markers.City_ID
Thank you.
You do not sum up the amounts here:
round( (D2.Donation_amount / D1.Donation_amount) *100, 2 )
So the result is calculated by the values of each first row:
round( (70 / 50) *100, 2 ) ==> 140
Use sum() to get the intended result:
round( (sum(D2.Donation_amount) / sum(D1.Donation_amount)) *100, 2 )

MySQL - Group By Year using 2 columns & Count

I have a table like this:
ID_____StartDate_____EndDate
----------------------------
1______05/01/2012___02/03/2013
2______06/30/2013___07/12/2013
3______02/17/2010___02/17/2013
4______12/10/2012___11/16/2013
I'm trying to get a count of the ID's that were active during each year. If the ID was active for multiple years, it would be counted multiple times. I don't want to "hardcode" years into my query because the data is over many many multiple years. (i.e. can't use CASE YEAR(StartDate) WHEN x then y or IF...
Desired Result from the table above:
YEAR_____COUNT
2010_____1
2011_____1
2012_____3
2013_____4
I've tried:
SELECT COUNT(ID)
FROM table
WHERE (DATE_FORMAT(StartDate, '%Y-%m') BETWEEN '2013-01' AND '2013-12'
OR DATE_FORMAT(EndDate, '%Y-%m') BETWEEN '2013-01' AND '2013-12')
of course this only is for the year 2013. I also tried:
SELECT YEAR(StartDate) AS 'Start Year', YEAR(EndDate) AS 'End Year', COUNT(id)
FROM table
WHERE StartDate IS NOT NULL
GROUP BY YEAR(StartDate);
though this gave me just those that started in a given year.
Assuming that there is an auxiliary table that contains consecutive numbers from 1 .. to X (where X must be grather than possible number of years in the table):
create table series( x int primary key auto_increment );
insert into series( x )
select null from information_schema.tables;
then the query might look like:
SELECT years.year, count(*)
FROM (
SELECT mm.min_year + s.x - 1 as year
FROM (
SELECT min( year( start_date )) min_year,
max( year( end_date )) max_year
FROM tab
) mm
JOIN series s
ON s.x <= mm.max_year - mm.min_year + 1
GROUP BY mm.min_year + s.x - 1
) years
JOIN tab
ON years.year between year( tab.start_date )
and year( tab.end_date )
GROUP BY years.year
;
see a demo: http://www.sqlfiddle.com/#!2/f49ab/14

MySql Query for generating report

I have one table which is having three fields:
Id, Creation Time, Fuel Level
Every two minutes we are getting data and inserting to database.For generating a fuel credit/debit statement i want to get starting(Stating of the day) and ending(End of the Day) Fuel Level.Can anyone help to form a query to generate this report?
Search parameters will be date range.
Id=10;creation time =2019-02-15 16:32:59;Fuel Level =20
I created one sample schema here
http://sqlfiddle.com/#!2/76dd5
First, for a query that provides the change in fuel for each vehicle for each day, you can use the following SQL:
SELECT trip_range.dt
, trip_range.vehicle_id
, st.fuel_content as start_fuel_content
, en.fuel_content as end_fuel_content
, en.fuel_content - st.fuel_content as fuel_change
FROM (
SELECT tp.vehicle_id, DATE(tp.creation_time) dt
, MIN(tp.creation_time) start_time
, MAX(tp.creation_time) end_time
FROM trip_parameters tp
GROUP BY tp.vehicle_id, DATE(tp.creation_time)
) as trip_range
JOIN trip_parameters st
ON st.vehicle_id = trip_range.vehicle_id
AND st.creation_time = trip_range.start_time
JOIN trip_parameters en
ON en.vehicle_id = trip_range.vehicle_id
AND en.creation_time = trip_range.end_time
WHERE trip_range.dt BETWEEN '2012-11-08' AND '2012-11-09'
If you want the Cumulative change in fuel across all vehicles for each day in the range, the following SQL should work:
SELECT dt, SUM(fuel_change) as fuel_change
FROM (
SELECT trip_range.dt
, en.fuel_content - st.fuel_content as fuel_change
FROM (
SELECT tp.vehicle_id, DATE(tp.creation_time) dt
, MIN(tp.creation_time) start_time
, MAX(tp.creation_time) end_time
FROM trip_parameters tp
GROUP BY tp.vehicle_id, DATE(tp.creation_time)
) as trip_range
JOIN trip_parameters st
ON st.vehicle_id = trip_range.vehicle_id
AND st.creation_time = trip_range.start_time
JOIN trip_parameters en
ON en.vehicle_id = trip_range.vehicle_id
AND en.creation_time = trip_range.end_time
WHERE trip_range.dt BETWEEN '2012-11-08' AND '2012-11-09'
) change_by_vehicle
GROUP BY 1
Hope this helps!
john...
Try below:
SELECT Id, CreationTime, FuelLevel
FROM MYTABLE
WHERE DATE(CreationTime) = CURDATE();
This gets the date part of CreationTime and compares against current date, thus returns all records created today.
here's a query that returns the output as:
DATE FUEL_CONTENT_AT_START_OF_DAY FUEL_CONTENT_AT_END_OF_DAY
Nov, 08 2012 4.6 3.6
Nov, 09 2012 11.6 5.6
Query
SELECT
DATE( startofday.creation_time) AS date,
startofday.fuel_content AS fuel_content_at_start_of_day,
(SELECT fuel_content FROM trip_parameters WHERE trip_paramid = max(endofday.trip_paramid) ) AS fuel_content_at_end_of_day
FROM
trip_parameters startofday
INNER JOIN trip_parameters endofday ON ( DATE( endofday.creation_time ) = DATE( startofday.creation_time) )
WHERE
DATE( startofday.creation_time) BETWEEN '2012-11-08' AND '2012-11-09'
GROUP BY
startofday.TRIP_PARAMID
HAVING
min( endofday.trip_paramid ) = startofday.trip_paramid
I have update the same on SQLFiddle, http://sqlfiddle.com/#!2/76dd5/67
The query works as
Get a row
Get all corresponding rows on the same day
Get the minimum and maximum ID on the same day
If the current row Id equals the minimum Id from the JOIN display it, else ignore
Use the maximum id in a sub-query to get the end of day fuel_content
Hope this helps