SQL query for Min() and grouping - mysql

My Table name is powerpro including data as following
+-----------+-------------------+---------------+
| record_no | date_time | phase1_energy |
+-----------+-------------------+---------------+
| | | |
| 1 | 12/01/14 12:00 AM | 234 |
| 2 | 12/01/14 01:00 AM | 230 |
| 3 | 12/01/14 02:00 AM | 220 |
| 4 | 12/01/14 03:00 AM | 222 |
| 5 | 13/02/14 12:00 AM | 233 |
| 6 | 13/02/14 01:00 AM | 234 |
| 7 | 13/02/14 02:00 AM | 220 |
| 8 | 13/02/14 03:00 AM | 220 |
| 9 | 14/03/14 12:00 AM | 234 |
| 10 | 14/03/14 01:00 AM | 231 |
| 11 | 14/03/14 02:00 AM | 219 |
| 12 | 14/03/14 03:00 AM | 216 |
+-----------+-------------------+---------------+
I want to get phase1_energy balance (from each day minimum reading deducting by next day minimum reading) back to 7 days from NOW()
I tried this:
SELECT a1.* FROM powerpro a1
INNER JOIN
(
select MIN(date_time) as min FROM powerpro
GROUP BY date(date_time)
) a2
ON a1.date_time = a2.min
WHERE date_time BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) AND NOW() ORDER BY date_time
But only got the minimum reading of each day as follows.
+-----------+-------------------+---------------+
| record_no | date_time | phase1_energy |
+-----------+-------------------+---------------+
| | | |
| 1 | 12/01/14 12:00 AM | 234 |
| 5 | 12/02/14 12:00 AM | 233 |
| 9 | 12/03/14 12:00 AM | 234 |
+-----------+-------------------+---------------+
Can anyone help me ? Thanks

If I understand correctly, for each date you want the min time (which you managed to get), and the next day's min time.
Here is how you can get that next day min time (EDIT: adding the energy of both days):
SELECT DATE(a1.date_time) AS `date`, a1.date_time AS this_day_min_read, a1.phase1_energy AS this_day_energy,
a4.date_time AS next_day_min_read, a4.phase1_energy AS next_day_energy
FROM powerpro a1
JOIN (SELECT DATE(date_time) `date`, MIN(date_time) AS `min`
FROM powerpro
GROUP BY DATE(date_time)
) a2 ON a1.date_time = a2.min
JOIN (SELECT DATE(date_time) `date`, MIN(date_time) AS `min`
FROM powerpro
GROUP BY DATE(date_time)
) a3 ON DATE(a1.date_time) = a3.date - INTERVAL 1 DAY
JOIN powerpro a4
ON a4.date_time = a3.min
WHERE date_time BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) AND NOW()
ORDER BY date_time
Hope this helps.

Related

SQL query to get AVG from columns and GROUP BY

I have a table like this which consists of several climatic measures (rain rates, temps, etc.)
mysql> select rain_rate, temperature, datetime from weather limit 10;
+--------------+---------------+----------------------+
| rain_rate | temperature | datetime |
+--------------+---------------+----------------------+
| 5.0000000000 | 24.4000000000 | 2017-02-08 16:00:56 |
| 1.0000000000 | 22.4000000000 | 2017-02-06 12:10:36 |
| 2.0000000000 | 28.7000000000 | 2017-02-02 13:57:15 |
| 5.0000000000 | 24.7000000000 | 2017-02-01 14:14:16 |
| 1.0000000000 | 16.1000000000 | 2017-01-08 06:01:26 |
| 2.0000000000 | 18.2000000000 | 2017-01-12 05:10:43 |
| 3.0000000000 | 11.9000000000 | 2017-01-10 06:20:54 |
| 4.0000000000 | 16.8000000000 | 2017-01-25 16:10:14 |
| 5.0000000000 | 24.4000000000 | 2016-12-18 23:10:56 |
| 4.0000000000 | 26.6000000000 | 2016-12-30 09:03:54 |
...
As can be seen, timestamps (datetime field) does not follow any pattern.
I want to get the last 24 average values of temperature and rain_rate by hour, and a column with the numerical value of the associated hour, in 24-hour format, ordered by hour asc.
As an example, if I executed the query today at 18:30 pm, it should return these 24 rows:
+-----------------+------------------+-------+
| avg(rain_rate) | avg(temperature) | hour |
+-----------------+------------------+-------+
| 3.5000000000 | 23.1000000000 | 19 | |
| 1.0000000000 | 22.6000000000 | 20 | |
| 3.5000000000 | 24.7000000000 | 21 | |-> hours of "yesterday"
| 4.5000000000 | 23.8000000000 | 22 | |
...
| 2.0000000000 | 26.3000000000 | 13 | |
| 1.5000000000 | 21.6000000000 | 14 | |
| 7.0000000000 | 23.4000000000 | 15 | |-> hours of "today"
| 2.5000000000 | 21.4000000000 | 16 | |
| 7.0000000000 | 21.2000000000 | 17 | |
| 3.0000000000 | 25.3000000000 | 18 | |
My best try so far:
select avg(rain_rate), avg(temperature), hour(datetime) as hour
from weather
where (datetime >= now() - interval 24 hour)
group by hour(datetime)
order by max(datetime) asc
It looks like that query returns the correct average values for the fields, but hour field does not seem to be ordered like I need nor corresponding to the mean values...
Any help is much appreciated.
Thanks in advance.
You want to average by hour for the past 24 hours.
Ok. Here is one way:
select date(datetime), hour(datetime),
avg(rain_rate), avg(temperature)
from weather
where (datetime >= now() - interval 24 hour)
group by date(datetime), hour(datetime)
order by min(datetime);
Note: 24 hours from the current time might be a little weird. You could get 25 rows of records (with two partial hours). You may want this where:
where datetime < curdate() + interval hour(now()) hour and
datetime >= curdate() + interval hour(now()) - 24 hour
I suppose you must try order by datetime.
The query must be like:
select avg(rain_rate), avg(temperature), hour(datetime) as hour
from weather
where (datetime >= now() - interval 24 hour)
group by hour(datetime)
order by datetime asc;
I hope i was help.

get all dates in the current month

i have table
userID | date | time
===================
1 | 2015-02-08 | 06:32
1 | 2015-02-08 | 05:36
1 | 2015-02-08 | 17:43
1 | 2015-02-08 | 18:00
1 | 2015-02-09 | 06:36
1 | 2015-02-09 | 15:43
1 | 2015-02-09 | 19:00
1 | 2015-02-10 | 05:36
1 | 2015-02-10 | 17:43
1 | 2015-02-10 | 18:00
2 | 2015-02-08 | 06:32
2 | 2015-02-08 | 05:36
2 | 2015-02-08 | 17:43
2 | 2015-02-08 | 18:00
2 | 2015-02-09 | 06:36
2 | 2015-02-09 | 15:43
2 | 2015-02-09 | 19:00
2 | 2015-02-10 | 05:36
2 | 2015-02-10 | 17:43
2 | 2015-02-10 | 18:00
But i want the number of records returned to be exactly the same as the number of days of the current month and get min time for in and max time for the out. if the current month has 28 days and only had two records it should bring:
userID | date | in | out
========================
1 | 2015-02-01 | |
1 | 2015-02-02 | |
1 | 2015-02-03 | |
1 | 2015-02-04 | |
1 | 2015-02-05 | |
1 | 2015-02-06 | |
1 | 2015-02-07 | |
1 | 2015-02-08 | 06:32 | 18:00
1 | 2015-02-09 | 06:36 | 19:00
1 | 2015-02-10 | 05:36 | 18:00
1 | 2015-02-11 | |
1 | 2015-02-12 | |
1 | 2015-02-13 | |
1 | 2015-02-14 | |
1 | 2015-02-15 | |
1 | 2015-02-16 | |
1 | 2015-02-17 | |
1 | 2015-02-18 | |
1 | 2015-02-19 | |
1 | 2015-02-20 | |
1 | 2015-02-21 | |
1 | 2015-02-22 | |
1 | 2015-02-23 | |
1 | 2015-02-24 | |
1 | 2015-02-25 | |
1 | 2015-02-26 | |
1 | 2015-02-27 | |
1 | 2015-02-28 | |
How can i modify my query to achieve the above result?
this is my query:
$sql = "SELECT
colUserID,
colDate,
if(min(colJam) < '12:00:00',min(colJam), '') as in,
if(max(colJam) > '12:00:00',max(colJam), '') as out
FROM tb_kehadiran
WHERE colDate > DATE_ADD(MAKEDATE($tahun, 31),
INTERVAL($bulan-2) MONTH)
AND
colDate < DATE_ADD(MAKEDATE($tahun, 1),
INTERVAL($bulan) MONTH)
AND
colUserID = $user_id
GROUP BY colUserID,colDate";
I had to think about this one. But probably the simpliest answer so far:
WITH AllMonthDays as (
SELECT n = 1
UNION ALL
SELECT n + 1 FROM AllMonthDays WHERE n + 1 <= DAY(EOMONTH(GETDATE()))
)
SELECT
DISTINCT datefromparts(YEAR(GETDATE()), MONTH(GETDATE()), n) As dates
, MIN(d.time) as 'In'
, MAX(d.time) as 'Out'
FROM AllMonthDays as A
LEFT OUTER JOIN
table as d on
DAY(d.date) = A.n
GROUP BY n,(d.date);
--- Test and tried in this environment: ---
use Example;
CREATE TABLE demo (
ID int identity(1,1)
,date date
,time time
);
INSERT INTO demo (date, time) VALUES
('2015-12-08', '06:32'),
('2015-12-08', '05:36'),
('2015-12-08', '17:43'),
('2015-12-08', '18:00'),
('2015-12-09', '06:36'),
('2015-12-09', '15:43'),
('2015-12-09', '19:00'),
('2015-12-10', '05:36'),
('2015-12-10', '17:43'),
('2015-12-10', '18:00')
;
WITH AllMonthDays as (
SELECT n = 1
UNION ALL
SELECT n + 1 FROM AllMonthDays WHERE n + 1 <= DAY(EOMONTH(GETDATE()))
)
SELECT
DISTINCT datefromparts(YEAR(GETDATE()), MONTH(GETDATE()), n) As dates
, MIN(d.time) as 'In'
, MAX(d.time) as 'Out'
FROM AllMonthDays as A
LEFT OUTER JOIN
demo as d on
DAY(d.date) = A.n
GROUP BY n,(d.date);
DROP table demo;
The way I've approached this problem in the past is to have a date table that is pre-populated for some years in the future.
You could create such a table, possibly defining columns for year, month and date, with indexes on year and month.
You can then use this table with a JOIN on your data to ensure that all dates are present in your results.
You need three things:
A list of dates.
A left join
Aggregation
So:
select d.dte, min(t.time), max(t.time)
from (select date('2015-02-01') as dte union all
select date('2015-02-02') union all
. .
select date('2015-02-28')
) d left join
t
on d.dte = t.date
group by d.dte
order by d.dte;
Try this
set #is_first_date = 0;
set #temp_start_date = date('2015-02-01');
set #temp_end_date = date('2015-02-28');
select my_dates.date,your_table_name.user_id, MIN(your_table_name.time), MAX(your_table_name.time) from
( select if(#is_first_date , #temp_start_date := DATE_ADD(#temp_start_date, interval 1 day), #temp_start_date) as date,#is_first_date:=#is_first_date+1 as start_date from information_schema.COLUMNS
where #temp_start_date < #temp_end_date limit 0, 31
) my_dates left join your_table_name on
my_dates.date = your_table_name.date
group by my_dates.date
Try This query
SELECT `date`, MIN(`time`) as `IN`, MAX('time') AS `OUT`
FROM `table_name` WHERE month(current_date) = month(`date`)
GROUP BY `date`;

sql query to add rows based on a time difference

i have a table that has the following columns : s.no,house_no,energy,time
i want to find the total energy for each house for every one hour.
table :
+-----+----------+---------------------+--------+
| sno | house_no | time | energy |
+-----+----------+---------------------+--------+
| 1 | 1 | 2014-10-20 10:00:00 | 5 |
| 2 | 1 | 2014-10-20 10:30:00 | 10 |
| 3 | 2 | 2014-10-20 10:00:00 | 7 |
| 4 | 1 | 2014-10-20 11:01:00 | 3 |
| 5 | 2 | 2014-10-20 11:00:00 | 20 |
+-----+----------+---------------------+--------+
i am trying for 10-11 am.But this query sums the energy of the rows whose time value is greater than 11 am also.
SELECT house_no, sum( energy ) AS sum, time
FROM main
GROUP BY house_no
HAVING (
TIMESTAMPDIFF(
MINUTE , time, '2014-10-20 11:00:00' ) >0)
the result is :
+----------+------+---------------------+
| house_no | sum | time |
+----------+------+---------------------+
| 1 | 18 | 2014-10-20 10:00:00 |
| 2 | 27 | 2014-10-20 10:00:00 |
+----------+------+---------------------+
but the actual answer should be:
+----------+------+---------------------+
| house_no | sum | time |
+----------+------+---------------------+
| 1 | 15 | 2014-10-20 10:00:00 |
| 2 | 7 | 2014-10-20 10:00:00 |
+----------+------+---------------------+
You have to group the time also based on the hours
SELECT house_no, sum( energy ) AS sum, time
FROM main
GROUP BY house_no,DATE_FORMAT(time,'%d %b %Y %H')
HAVING (
TIMESTAMPDIFF(
MINUTE , time, '2014-10-20 11:00:00' ) >0)
DEMO

Confuse query add date not in table for mysql

excuse me,
i will add date if that date not in table on mysql
example i have table
ID | name | date | clock in | clock out
---------------------------------------------------------------
1001 | A | 2013-09-18 | 09:40 | 17:15
1001 | A | 2013-09-20 | 08:20 | 17:35
1001 | A | 2013-09-21 | 08:40 | 17:40
1001 | A | 2013-09-23 | 08:10 | 17:50
so, how to add date in to no table and set clock in and clock out set null
example
ID | name | date | clock in | clock out
---------------------------------------------------------------
1001 | A | 2013-09-18 | 09:40 | 17:15
1001 | A | 2013-09-19 | null | null
1001 | A | 2013-09-20 | 08:40 | 17:40
1001 | A | 2013-09-21 | 08:10 | 17:50
1001 | A | 2013-09-22 | null | null
1001 | A | 2013-09-23 | 08:10 | 17:50
thanks
This is what you need if you're still interested:
SELECT
COALESCE(id,1001) id,
COALESCE(name,'A') name,
fixed_days.fixed_date,
clockin,clockout
FROM t
RIGHT JOIN
(SELECT CURDATE() as fixed_date
UNION ALL SELECT CURDATE() - INTERVAL 1 day
UNION ALL SELECT CURDATE() - INTERVAL 2 day
UNION ALL SELECT CURDATE() - INTERVAL 3 day
UNION ALL SELECT CURDATE() - INTERVAL 4 day
UNION ALL SELECT CURDATE() - INTERVAL 5 day
UNION ALL SELECT CURDATE() - INTERVAL 6 day) AS fixed_days
ON t.record_date = fixed_days.fixed_date
WHERE fixed_days.fixed_date <= (select max(record_date) from t);
SQL Fiddle..

MySQL: Finding Maximum Value for a Column for each location and server

I have the following table:
++++++++++++++++++++++++++++++++++++++++++++++++++
| location | server | datetime | max_cpu |
++++++++++++++++++++++++++++++++++++++++++++++++++
| Chicago | 1 | 2013-05-01 00:00 | 10 |
| Chicago | 1 | 2013-05-01 01:00 | 15 |
| Chicago | 1 | 2013-05-01 02:00 | 11 |
| Chicago | 2 | 2013-05-01 00:00 | 8 |
| Chicago | 2 | 2013-05-01 01:00 | 12 |
| Chicago | 2 | 2013-05-01 02:00 | 13 |
| Atlanta | 1 | 2013-05-01 00:00 | 11 |
| Atlanta | 1 | 2013-05-01 01:00 | 12 |
| Atlanta | 1 | 2013-05-01 02:00 | 19 |
| Atlanta | 2 | 2013-05-01 00:00 | 21 |
| Atlanta | 2 | 2013-05-01 01:00 | 15 |
| Atlanta | 2 | 2013-05-01 02:00 | 17 |
I need the maximum CPU for each box in each location for a given day, e.g.
++++++++++++++++++++++++++++++++++++++++++++++++++
| location | server | datetime | max_cpu |
++++++++++++++++++++++++++++++++++++++++++++++++++
| Chicago | 1 | 2013-05-01 01:00 | 15 |
| Chicago | 2 | 2013-05-01 02:00 | 13 |
| Atlanta | 1 | 2013-05-01 02:00 | 19 |
| Atlanta | 2 | 2013-05-01 00:00 | 21 |
I know how to do this for a single criteria (e.g. just location) and tried to expand upon that (see below) but it is not giving me the output I need.
SELECT a.location, a.server, a.datetime, a.max_cpu
FROM mytable as a INNER JOIN
(
SELECT location, server, max(max_cpu) as max_cpu
FROM mytable
GROUP BY location, server
)
AS b ON
(
a.location = b.location
AND a.server = b.server
AND a.max_cpu = b.max_cpu
)
You can do this by finding the max cpu and joining back to the original table.
It seems that you want the time of the max as well as the amount (this is not clearly stated in the text, but clear in the results):
select t.*
from mytable t join
(select location, server, DATE(datetime) as thedate, MAX(max_cpu) as maxmaxcpu
from mytable t
group by location, server, DATE(datetime)
) lsd
on lsd.location = t.location and lsd.server = t.server and
lsd.thedate = DATE(t.datetime) and lsd.maxmaxcpu = t.max_cpu
This calculates the maxcpu on each day and then joins back to get the appropriate row or rows in the original data. If there is more than one record with the max, you'll get all the records. If you only want one, you can add group by location, server, day(datetime) to the query.
This better answers the "for a given day" part of the question. Since you can ignore the time, this avoids that date hacky thing, is a tad simpler, and if multiple times have the same CPU for that server, it doesn't show duplicates:
select distinct a.location, a.server, a.datetime, a.max_cpu
from
mytable a
inner join (
select location, server, max(max_cpu) as max
from mytable
where
datetime >= ? -- start of day
and datetime < ? -- start of next day
group by location, server
) b on a.location=b.location and a.server=b.server and a.max_cpu as max
where
a.datetime >= ? -- start of day
a.and datetime < ? -- start of next day
Query (works only if max_cpu is unique per location, server and Date ):
SQLFIDDLEExample
SELECT t1.*
FROM Table1 t1
WHERE t1.max_cpu = (SELECT MAX(t2.max_cpu)
FROM Table1 t2
WHERE t2.location = t1.location
AND t2.server = t1.server
AND DATE(t2.datetime) = DATE(t1.datetime))
Result:
| LOCATION | SERVER | DATETIME | MAX_CPU |
------------------------------------------------------------
| Chicago | 1 | May, 01 2013 01:00:00+0000 | 15 |
| Chicago | 2 | May, 01 2013 02:00:00+0000 | 13 |
| Atlanta | 1 | May, 01 2013 02:00:00+0000 | 19 |
| Atlanta | 2 | May, 01 2013 00:00:00+0000 | 21 |