I have the following MySQL table:
My requirements are,At a 30-minute time interval query data,with no need for group by,This concept,For the first time encounter this kind of question,How can I achieve that effect,The interval between the last one and the next is 30 minutes
I think this does what you want:
select t.*
from t
where t.time = (select min(t2.time)
from t t2
where floor(to_seconds(t2.time) / (30 * 60)) = floor(to_seconds(t.time) / (30 * 60))
);
the other day think of answer:
SELECT FROM_
UNIXTIME(UNIX_TIMESTAMP(t.Time)- UNIX_TIMESTAMP(t.Time)%(15*60))
AS timekey,DB33,Stream,`View`,Coil
FROM (select DB33,Stream,`View`,Time,Coil from running_check where
DB33=#{DB33} ORDER BY id desc limit 10000) as t
GROUP BY timekey
Related
I have a table in MySQL with some data of a temperature sensor. I have 1 row per minute. I would like to perform a query to know whether there was any span of 1 hour where the average temperature was greater than 4 degrees. I know how to perform a query where a single row was above 4:
SELECT * FROM sensor WHERE t>4
But in my case, I want to know whether there was a 1 hour period where the average temperature was over 4, not only a single row.
Not sure how to write such query...
One method is:
select s.*
from sensor s
where t > 4 and
not exists (select 1
from sensor s2
where s2.datetime >= s.datetime and
s2.datetime < s.datetime + interval 1 hour and
s2.t <= 4
);
EDIT:
Arggh. The question asks about the average temperature, not any temperature (the question is quite clear, I just misread it).
Here is a variation to handle that:
select s.*,
(select avg(s2.t)
from sensor s2
where s2.datetime >= s.datetime and
s2.datetime < s.datetime + interval 1 hour
) as avg_t
from t
having avg_t > 4;
This uses an extension to MySQL where the having clause can make use of a column alias for filtering.
SELECT DATE_FORMAT(DATE_TIME_FIELD, '%Y-%m-%d %H') AS DATE_TIME_HOUR
FROM sensor
GROUP BY DATE_FORMAT(DATE_TIME_FIELD, '%Y-%m-%d %H')
HAVING AVG(T)>4
Another method is:
SELECT *,
AVG(`t`) AS `avg_t`,
DATE_FORMAT(`date`, '%Y-%m-%d %H') AS `date_and_hour`
FROM `sensor`
GROUP BY DATE_FORMAT(`date`, '%Y-%m-%d %H')
HAVING `avg_t` > 4;
We have a below query which takes approximately 6-8 secs to execute.
Total number of records : 522954
(SELECT
*
FROM
tbl_insights_copy
WHERE insightscat = 21
AND submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC
LIMIT 5)
UNION
(SELECT
*
FROM
tbl_insights_copy
WHERE insightscat = 22
AND submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC
LIMIT 5)
UNION
(SELECT
*
FROM
tbl_insights_copy
WHERE insightscat = 23
AND submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC
LIMIT 5)
UNION
(SELECT
*
FROM
tbl_insights_copy
WHERE insightscat = 24
AND submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC
LIMIT 5)
Can someone help to optimize this query as to reduce the execution time.
Thanks in advance.
The only thing you are changing between one select and another, is the filter value of the column insightscat I am not sure that this is what you want but....
You may try the IN instruction for this. Example:
SELECT
*
FROM
tbl_insights_copy
WHERE insightscat in (20,21,22,23,24)
AND submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC
For this query:
SELECT ic.*
FROM tbl_insights_copy ic
WHERE insightscat = 21 AND
submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC
LIMIT 5
You want an index on tbl_insights_copy(insightscat, submittedon).
This should work for all the subqueries. This is probably the best approach with MySQL.
SELECT t1.*
FROM (SELECT t.* ,ROW_NUMBER() OVER (ORDER BY insightscat) AS Row
FROM
(select * from
tbl_insights_copy
WHERE insightscat in (20,21,22,23,24)
AND submitedon >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY))
ORDER BY submitedon DESC ) as t ) t1
WHERE Row <= 5
Without SHOW CREATE TABLE, I am going to have to guess that you do not have the optimal
INDEX(insightscat, submitedon)
Since the SELECTs are distinct, use UNION ALL instead of the default UNION DISTINCT. This will avoid an unnecessary (but fast) de-dup pass over the 20 rows.
If you want 20 rows
If so, my suggestions above might be best.
If you want 6 rows
If you want only the latest 5 from any of those insightscats, then there are 3 possibilities.
Plan A
What Developer90 says in his Comment.
Plan B
( SELECT ... ORDER BY ORDER BY submitedon DESC LIMIT 5)
UNION ALL
( SELECT ... ORDER BY ORDER BY submitedon DESC LIMIT 5)
UNION ALL
( SELECT ... ORDER BY ORDER BY submitedon DESC LIMIT 5)
UNION ALL
( SELECT ... ORDER BY ORDER BY submitedon DESC LIMIT 5)
ORDER BY ORDER BY submitedon DESC LIMIT 5;
Each SELECT is very fast with my index. Then, the 20 rows of the UNION get sorted again and LIMIT 5 is applied. Again, very fast.
Using the IN as suggested by Developer90, may or may not effectively use my index. What version are you using?
Plan C
This option is hit or miss. That is, its performance depends heavily on the distribution of the data as to whether it will be very fast or very slow: Developer90 + INDEX(submitedon) (not including insightscat).
I'm trying to group my timestamp every 30 minutes.
I want my result to be like this:
2016-03-09 00:00:00
2016-03-09 00:30:00
2016-03-09 01:00:00
Instead, my results are this:
2016-03-09 00:00:23
2016-03-09 00:35:02
2016-03-09 01:00:03
The query that I'm using is this
SELECT timestamp
FROM a.tablename
WHERE name = 'example' AND timestamp LIKE '2016-03-09%'
GROUP BY ROUND(((60/30) * HOUR(timestamp) + FLOOR( MINUTE(timestamp) / 30)));
How can I have my desired results? I've researched other answers on SO and non of the answers helped
Here's the basic query to group by 30 minutes interval.
SELECT
FROM_UNIXTIME(ROUND(UNIX_TIMESTAMP(timestamp)/(30* 60)) * (30*60)) thirtyHourInterval
FROM tablename
GROUP BY ROUND(UNIX_TIMESTAMP(timestamp)/(30* 60));
Note: ROUND() may lead you towards wrong output. Use the following query instead. Look at the following example:
SELECT ROUND(3.7), ROUND(4.2);
Result: 4 4.
Both lies in the same segment. The same holds for the above query while rounding the timestamp of different segments might fall in the same segment thus leading towards wrong output
[The following query is Recommended]
SELECT
FROM_UNIXTIME((UNIX_TIMESTAMP(`timestamp`) DIV (30* 60) ) * (30*60)) thirtyHourInterval
FROM tablename
GROUP BY UNIX_TIMESTAMP(`timestamp`) DIV (30* 60)
SQL FIDDLE DEMO
Alternatively you can adopt the following query.
SELECT
FROM_UNIXTIME(ROUND(UNIX_TIMESTAMP(timestamp)/(30* 60)) * (30*60)) thirtyHourInterval
FROM tablename
GROUP BY ( 4 * HOUR( `timestamp` ) + FLOOR( MINUTE( `timestamp` ) / 30 ));
Relatedpost
One method is to use to_seconds(), truncate the value, and then re-create the datetime value:
select date_add(0, interval floor(to_seconds(timestamp) / (30 * 60)) second) as timestamp
from a.tablename
where name = 'example' and timestamp >= '2016-03-09' and timestamp < '2016-03-10'
group by date_add(0, interval floor(to_seconds(timestamp) / (30 * 60)) second)
order by 1;
I am collecting data every five minutes and entering it into a MySQL database. I would like to extract the most recent row that's over 2 hours old, followed by over 1 hour old, followed by the most recent row.
I was thinking something along the lines of the following, but I think this will get me the last row of each hour. Meaning if I run the query at 8:05 I might get back rows from 6:57, 7:57 and 8:02, the last 2 of which are much less than an hour apart.
SELECT *
FROM (
SELECT *
FROM mytable
ORDER BY Date DESC
GROUP BY HOUR(Date) LIMIT 3
) x
ORDER BY Date ASC
Thanks for any help or suggestions you can provide.
SELECT * FROM (
SELECT * FROM mytable
WHERE `Date`<DATE_SUB(NOW(), INTERVAL 2 HOUR)
ORDER BY DATE DESC LIMIT 1
)
UNION
SELECT * FROM (
SELECT * FROM mytable
WHERE `Date`<DATE_SUB(NOW(), INTERVAL 1 HOUR)
ORDER BY DATE DESC LIMIT 1
)
UNION
SELECT * FROM (
SELECT * FROM mytable
ORDER BY DATE DESC LIMIT 1
)
ORDER BY `Date`ASC
I want to get the value of users visiting my page for 10 days in a chart. I need to COUNT() all the values from the last ten days.
The best layout would be
Day|COUNT(ip)
1 - 10
2 - 12
3 - 52
......
I hope you understand what I mean.
Can MySQL do this directly or need I to do this in PHP in 10 seperate querys?
Regards,
Moritz
Update with Tablestructure:
Id (Auto Increment)|Time (Unix Timestamp)|Ip|Referer
This should run fast for you
SELECT COUNT(ip) ipcount,dt FROM
(
SELECT ip,DATE(FROM_UNIXTIME(`Time`)) as dt FROM mytable
WHERE `Time` > TO_UNIXTIME(NOW() - INTERVAL 10 DAY)
) A GROUP BY dt;
Make sure you have an index on Time
ALTER TABLE mytable ADD INDEX TimeIndex (`Time`);
This will give you results with actual date values:
SELECT
COUNT(DISTINCT ip),
FROM_UNIXTIME(Time, '%m/%d/%Y') AS Day
FROM
tbl
WHERE
Time >= UNIX_TIMESTAMP(DATE_ADD(CURDATE(), INTERVAL -10 DAY))
GROUP BY
FROM_UNIXTIME(Time, '%m/%d/%Y')
try this:
SELECT CAST(DATE(FROM_UNIXTIME(`Time`)) AS CHAR) as dateoftime, COUNT(Ip) as cnt
FROM tablename
WHERE DATE(FROM_UNIXTIME(`Time`)) > DATE_SUB(current_timestamp, INTERVAL 10 DAY)
GROUP BY CAST(DATE(FROM_UNIXTIME(`Time`)) AS CHAR)