I have a database of measurements for different locations that is taken every 1 hour.
ID | LOCATION_ID | CMS | DATE
6 | C | 7 | 2014-11-27 12:00:00
5 | B | 3 | 2014-11-27 12:00:00
4 | A | 19 | 2014-11-27 12:00:00
3 | C | 9 | 2014-11-27 11:00:00
2 | B | 8 | 2014-11-27 11:00:00
1 | A | 11 | 2014-11-27 11:00:00
I need to select the highest cms for each unique location, within the last 3 hours. For example;
ID | LOCATION_ID | CMS | DATE
3 | C | 9 | 2014-11-27 11:00:00
2 | B | 8 | 2014-11-27 11:00:00
4 | A | 19 | 2014-11-27 12:00:00
I am using the below MySQL to return the max, but I am missing the final piece. What do I need to complete the statement?
SELECT MAX(cms) as value_of_rain
FROM `rainfall`
WHERE `date` >= SUBDATE( NOW( ) , INTERVAL 3 HOUR )
You are missing the grouping statement using GROUP BY like
SELECT MAX(cms) as value_of_rain
FROM `rainfall`
WHERE `date` >= SUBDATE( NOW( ) , INTERVAL 10 MINUTE )
GROUP BY LOCATION_ID
Related
Given a table with a datetime column, I want to get the 4 week moving average number of entries per hour with the day of week for each result.
So for instance, between Oct 1st and Oct 13th, I'd like to get back a result that shows the 4 week rolling average for number of rows grouped by hour and dayofweek.
What I have so far gets me the 4 week hourly totals, but not rolling totals:
SELECT
DAYOFWEEK(start_time) as DOW,
date_format( start_time, '%H' ) as 'HOUR',
count( * ) as 'count'
FROM mytable
WHERE start_time >='2017-08-01' and start_time <= '2017-08-29'
GROUP BY DAYOFWEEK(start_time),date_format( start_time, '%H' )
Here is a partially tested approach.
It uses date parameters to ensure consistency of the where clauses. Other parameters are also used to control the hourly bucket (I used 3 in limited testing), and the number of weeks (I used 0 in testing as I had a very small set of rows).
The first subquery is used to produce "ranges" which when joined to the source rows will place those rows into each "rolling n hourly range". Those ranges are defined by using a date_format output YYYYMMDDHH which are strings, and then the data is also forced to this same string format for joining, so if being used on a large table this may cause performance issues (yes, not sargable, I don't like it either).
This solution may be seen working here at SQL Fiddle
Schema Setup:
CREATE TABLE `myTable` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
`start_time` datetime,
PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;
INSERT INTO MyTable
(`start_time`)
VALUES
('2017-08-01 00:01:00'),
('2017-08-01 00:15:00'),
('2017-08-01 00:29:00'),
## more here, 3 rows per hour over a narrow date range
('2017-08-03 08:01:00'),
('2017-08-03 08:15:00'),
('2017-08-03 08:29:00')
;
Query
set #start_time := '2017-08-02';
set #num_hrs := 4; -- controls length of rolling period e.g. 4 hours each
set #num_weeks := 4; -- controls the date date
set #end_time := date_add(#start_time, INTERVAL ((7 * #num_weeks)+1) DAY);
SELECT
DOW
, hour_of_day
, COUNT(*) period_count
, (COUNT(*) * 1.0) / #num_hrs rolling_av
FROM (
## build a set of ranges in YYYYMMDDHH format differing by the wanted number of hours
SELECT
id
, DATE_FORMAT(date_add(start_time, INTERVAL (#num_hrs*-1) HOUR), '%Y%m%d%H') as range_start
, DATE_FORMAT(start_time, '%Y%m%d%H') as range_end
FROM mytable
WHERE start_time >= #start_time and start_time < #end_time
) R
INNER JOIN (
SELECT
start_time
, DAYOFWEEK(start_time) as DOW
, date_format(start_time, '%H' ) as hour_of_day
FROM MyTable
WHERE start_time >= #start_time and start_time < #end_time
) T ON DATE_FORMAT(T.start_time, '%Y%m%d%H') >= R.range_start
AND DATE_FORMAT(T.start_time, '%Y%m%d%H') <= R.range_end
GROUP BY
DOW, hour_of_day
ORDER BY
DOW, hour_of_day
;
Results:
| DOW | hour_of_day | period_count | rolling_av |
|-----|-------------|--------------|------------|
| 4 | 00 | 36 | 12 |
| 4 | 01 | 36 | 12 |
| 4 | 02 | 36 | 12 |
| 4 | 03 | 36 | 12 |
| 4 | 04 | 36 | 12 |
| 4 | 05 | 36 | 12 |
| 4 | 06 | 36 | 12 |
| 4 | 07 | 36 | 12 |
| 4 | 08 | 36 | 12 |
| 4 | 09 | 36 | 12 |
| 4 | 10 | 36 | 12 |
| 4 | 11 | 36 | 12 |
| 4 | 12 | 36 | 12 |
| 4 | 13 | 36 | 12 |
| 4 | 14 | 36 | 12 |
| 4 | 15 | 36 | 12 |
| 4 | 16 | 36 | 12 |
| 4 | 17 | 36 | 12 |
| 4 | 18 | 36 | 12 |
| 4 | 19 | 36 | 12 |
| 4 | 20 | 36 | 12 |
| 4 | 21 | 27 | 9 |
| 4 | 22 | 18 | 6 |
| 4 | 23 | 9 | 3 |
I am a web developer and tried to search for the solution on a mysql query.I am unable to get the right solution for the count() function to return zero.
The count() function doesnot return zero for all dates.
The query is as below . can anyone help me on this.
SELECT
count(stat_id) as typeSuccess,
device_type as typeName,
YEARWEEK(date_auth) as date
FROM auth_stat
WHERE
AUTH_RESULT = 'SUCCESS' AND
date_auth BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 WEEK) AND CURDATE()
GROUP BY YEARWEEK(date_auth), device_type
ORDER BY YEARWEEK(date_auth)
The query that i tried to form is
select
date_auth,
count(stat_id) as typeSuccess,
device_type as typeName,
YEARWEEK(date_auth) as date
from
(
select #curDate := Date_Add(#curDate, interval 1 day) as MyJoinDate
from
(
select #curDate := CURDATE()
) sqlvars, auth_stat limit 18
) dateAll
LEFT JOIN auth_stat U on dateAll.MyJoinDate = U.date_auth
group by dateAll.MyJoinDate
Actual ouput :
+------------+-------------+
| date | typeSuccess |
+------------+-------------+
| 2015-03-18 | 11 |
+------------+-------------+
Expected Output:
+------------+-------------+
| date | typeSuccess |
+------------+-------------+
| 2015-03-18 | 11 |
| 2015-03-19 | 0 |
| 2015-03-20 | 0 |
+------------+-------------+
I believe all you want to do is just this
SELECT
SUM(AUTH_RESULT='SUCCESS') as numSuccess,
YEARWEEK(date_auth) as date
FROM auth_stat
WHERE date_auth BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 WEEK) AND CURDATE()
GROUP BY YEARWEEK(date_auth), device_type
ORDER BY YEARWEEK(date_auth)
basically all i'm doing is telling MySQL to sum up the boolean value (0 or 1) when auth_result is a success.. SUM() will return a 0 for a particular week if there is no successes in that week
The main issue is you were filtering out all non successful auth_results which would then not be counted. so remove that from the where and you should be good!
if you want it per day then you can do this
SELECT
SUM(AUTH_RESULT='SUCCESS') as numSuccess,
DATE(date_auth) as date
FROM auth_stat
WHERE date_auth BETWEEN DATE_SUB(CURDATE(), INTERVAL 6 WEEK) AND CURDATE()
GROUP BY DATE(date_auth), device_type
ORDER BY DATE(date_auth)
SQLFIDDLE FOR BOTH RESULTS
try
SELECT COUNT(statid), dates.auth_date
FROM
( SELECT DISTINCT auth_date
FROM Table1
WHERE auth_date BETWEEN '2015-03-06' AND '2015-03-09' -- or whatever
) AS dates
LEFT JOIN Table1 ON TRUE
AND Table1.auth_date = dates.auth_date
AND table1.auth_result = 'SUCCESS'
GROUP BY dates.auth_date
ORDER BY dates.auth_date
as desribed here: http://sqlfiddle.com/#!9/84faf/2
for eg data:
+--------+-------------+------------+
| statid | auth_result | auth_date |
+--------+-------------+------------+
| 1 | SUCCESS | 2015-03-05 |
| 2 | SUCCESS | 2015-03-05 |
| 3 | SUCCESS | 2015-03-05 |
| 4 | OTHER | 2015-03-06 |
| 5 | OTHER | 2015-03-06 |
| 6 | OTHER | 2015-03-06 |
| 7 | SUCCESS | 2015-03-07 |
| 8 | SUCCESS | 2015-03-07 |
| 9 | SUCCESS | 2015-03-07 |
| 10 | OTHER | 2015-03-08 |
| 11 | SUCCESS | 2015-03-08 |
| 12 | OTHER | 2015-03-08 |
| 13 | SUCCESS | 2015-03-09 |
| 14 | SUCCESS | 2015-03-09 |
| 15 | SUCCESS | 2015-03-09 |
| 16 | OTHER | 2015-03-10 |
| 17 | OTHER | 2015-03-10 |
| 18 | SUCCESS | 2015-03-10 |
| 19 | OTHER | 2015-03-11 |
+--------+-------------+------------+
eg output:
+---------------+-------------------------+
| count(statid) | auth_date |
+---------------+-------------------------+
| 0 | March, 06 2015 00:00:00 |
| 3 | March, 07 2015 00:00:00 |
| 1 | March, 08 2015 00:00:00 |
| 3 | March, 09 2015 00:00:00 |
+---------------+-------------------------+
It is not beautiful but hope it helps:
SELECT
date_auth,
count(stat_id) as typeSuccess,
device_type as typeName,
YEARWEEK(date_auth) as date
FROM
(
SELECT
DATE(DATE_ADD(NOW(), interval tmp.id day)) AS MyJoinDate
FROM (SELECT 1 as id
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9
UNION ALL SELECT 10
UNION ALL SELECT 11
UNION ALL SELECT 12
UNION ALL SELECT 13
UNION ALL SELECT 14
UNION ALL SELECT 15
UNION ALL SELECT 16
UNION ALL SELECT 17
UNION ALL SELECT 18
) AS tmp
) dateAll
LEFT JOIN auth_stat U on dateAll.MyJoinDate = U.date_auth
group by dateAll.MyJoinDate
I have tried adding the query as below. It stills returns me records that have the counts and not the dates with the count as zero.
SELECT COUNT(stat_id), dates.date_auth
FROM
( SELECT DISTINCT date_auth
FROM auth_stat
WHERE date_auth BETWEEN DATE_SUB(CURDATE(), INTERVAL 20 DAY) AND CURDATE()
) AS dates
LEFT JOIN auth_stat ON TRUE
AND auth_stat.date_auth = dates.date_auth
AND auth_stat.auth_result = 'SUCCESS'
GROUP BY dates.date_auth
ORDER BY dates.date_auth
Output result for the above query:
COUNT(stat_id) date_auth Ascending 1
1 2015-03-05 00:00:00
1 2015-03-06 00:00:00
11 2015-03-18 00:00:00
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.
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
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..