Getting the newest record from a database Multiple queries - mysql

I have a mysql database with vehicles records. I need a fast query that will return the newest records of those records that were updated within the last 4 minutes. For example vehicle "A" may be updated several times a minute so it will appear many times within the last 4min. Same with vehicle B C etc. I need only the most recent entries for each vehicle within a 4 min window. I have tried like this
SELECT *
FROM yourtable AS a
WHERE a.ts =
(SELECT MAX(ts)
FROM yourtable AS b
WHERE b.ts > NOW() - INTERVAL 5 MINUTE
AND b.name = a.name)
but it takes too long to produce results >10seconds.

You don't need the self-join.
select max(ts), name from Table1
where ts > NOW() - INTERVAL 5 MINUTE
group by name

To get all the rows for the latest updates and not only the name and timestamp:
SELECT t.*
FROM
TableX AS t
JOIN
( SELECT name
, MAX(ts) AS maxts
FROM TableX
WHERE ts > NOW() - INTERVAL 4 MINUTE
GROUP BY name
) AS grp
ON grp.name = t.name
AND grp.maxts = t.ts
You'll need at least an index on the timestamp column for this query.

Related

Getting missing time period value with an interval in My SQL

I'm trying to fetch the records with half an hour time interval of the current day with concern data count for that time period.
So, my output came as expected. But, If count(no records) on the particular time period let's say 7:00 - 7:30 I'm not getting that record with zero count.
My Query as follows :
SELECT time_format( FROM_UNIXTIME(ROUND(UNIX_TIMESTAMP(start_time)/(30* 60)) * (30*60)) , '%H:%i')
thirtyHourInterval , COUNT(bot_id) AS Count FROM bot_activity
WHERE start_time BETWEEN CONCAT(CURDATE(), ' 00:00:00') AND CONCAT(CURDATE(), ' 23:59:59')
GROUP BY ROUND(UNIX_TIMESTAMP(start_time)/(30* 60))
For reference of my output :
We need a source for that 7:30 row; a row source for all the time values.
If we have a clock table that contains all of the time values we want to return, such that we can write a query that returns that first column, the thirty minute interval values we want to return,
as an example:
SELECT c.hhmm AS thirty_minute_interval
FROM clock c
WHERE c.hhmm ...
ORDER BY c.hhmm
then we can do an outer join the results of the query with the missing rows
SELECT c.hhmm AS _thirty_minute_interval
, IFNULL(r._cnt_bot,0) AS _cnt_bot
FROM clock c
LEFT
JOIN ( -- query with missing rows
SELECT time_format(...) AS thirtyMinuteInterval
, COUNT(...) AS _cnt_bot
FROM bot_activity
WHERE
GROUP BY time_format(...)
) r
ON r.thirtyMinuteInterval = c.hhmm
WHERE c.hhmm ...
ORDER BY c.hhmm
The point is that the SELECT will not generate "missing" rows from a source where they don't exist; we need a source for them. We don't necessarily have to have a separate clock table, we could have an inline view generate the rows. But we do need to be able to SELECT those value from a source.
( Note that bot_id in the original query is indeterminate; the value will be from some row in the collapsed set of rows, but no guarantee which value. (If we add ONLY_FULL_GROUP_BY to sql_mode, the query will throw an error, like most other relational databases will when non-aggregate expressions in the SELECT list don't appear in the GROUP BY are aren't functionally dependent on the GROUP BY )
EDIT
In place of a clock table, we can use an inline view. For small sets, we could something like this.
SELECT c.tmi
FROM ( -- thirty minute interval
SELECT CONVERT(0,TIME) + INTERVAL h.h+r.h HOUR + INTERVAL m.mm MINUTE AS tmi
FROM ( SELECT 0 AS h UNION ALL SELECT 1 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
) h
CROSS JOIN ( SELECT 0 AS h UNION ALL SELECT 12 ) r
CROSS JOIN ( SELECT 0 AS mm UNION ALL SELECT 30 ) m
ORDER BY tmi
) c
ORDER
BY c.tmi
(Inline view c is a standin for a clock table, returns time values on thirty minute boundaries.)
That's kind of ugly. We can see where if we had a rowsource of just integer values, we could make this much simpler. But if we pick that apart, we can see how to extend the same pattern to generate fifteen minute intervals, or shorten it to generate two hour intervals.

Selecting between the MIN date and MIN date + 11 months - MySQL

I have a table that lists an ID, a month, and a value. I'd like to query this table to find the min(month) where value <= 0.
I'm having trouble writing this in a way that doesn't call the same table multiple times as the table is about 10mm rows.
So far, what I've written uses a HAVING clause to check if the month between min(month) and min(month) + 11 but it isn't functioning correctly. The query returns no data.
select id, month from table
group by id
having month between min(month) and date_add(min(month), interval 11 month)
Is there a clean way to do this without nesting queries and calling the same table multiple times?
You basically need to scan the table twice. Basically, the query is something like this:
select t.*
from t join
(select id, min(yyyymm) as minyyyymm
from t
where val < 0
group by id
) tt
on t.id = tt.id and t.yyyymm >= minyyyymm and
t.yyyymm <= minyyyymm + interval 11 month;
One option for making this faster is to materialize the subquery and add an index on id.

Select rows if column has same value more times

I have a column named log which contains logging information. I need a query to select all rows in which the value today appears two times or three times in my log column.
id log
1 today, yesterday, today, tomorrow, today
2 now, today, now
3 now, today, today
Select id from table if `today` appears three times in log column
The id:1 will be selected
This will do your job:
select * from table where ROUND (
(
LENGTH(log)
- LENGTH( REPLACE ( log, "today", "") )
) / LENGTH("today")
) >=3
Try this :
select * from yourtable a
inner join (
select max(id) as id,log,
sum(case when log = 'today' then 1 else 0 end) as c
from yourtable
group by log
) b on b.id = a.id and b.cnt = 3
Use the GROUP BY clause with HAVING
SELECT log
FROM tbl
GROUP BY log
HAVING COUNT(*) >= 2

Looping over a single column in mysql

I have a table that looks like this and i want to know the number of entries that are registered over a six hour time period and display that period which has max number of entries.
Time
09:42:29
10:37:28
15:18:49
15:28:34
16:43:51
18:14:10
18:26:06
18:26:14
So for each element in Time column, i will include a 6 hour period starting from that element and count how many entries in that column will fall in that period.
Ex 09:42:29 will have the end period has 15:42:29 and it should have count as 4 (09:42:29,10:37:28
15:18:49,15:28:34).
So do this for each element in Time Column and whichever element has max count, that will be the starting time of the period and display the start and end period accordingly.
Help me with writing a mysql query for this. Thank You!!!
Hope it helps
select
T.TimeStart,
T.TimeEnd,
COUNT(*)
from (
select
T.Time TimeStart,
date_add(T.Time,INTERVAL 6 HOUR) TimeEnd
from TimeTable T
) T
inner join TimeTable T2 on
T2.Time between T.TimeStart and T.TimeEnd
group by
T.TimeStart,
T.TimeEnd
The code below is for MSSQL but it works as expected and should give you some guidelines how the example above could be used
WITH TimeTable([Time]) AS (
select
CONVERT(DATETIME,a.a)
from (
values
('09:42:29'),
('10:37:28'),
('15:18:49'),
('15:28:34'),
('16:43:51'),
('18:14:10'),
('18:26:06'),
('18:26:14'))a(a)
)
select
convert(time(7),T.TimeStart)TimeStart,
convert(time(7),T.TimeEnd)TimeEnd,
COUNT(*) [Ocorrences]
from (
select
T.Time TimeStart,
DATEADD(HOUR,6,T.Time) TimeEnd
from TimeTable T
) T
inner join TimeTable T2 on
T2.Time between T.TimeStart and T.TimeEnd
group by
T.TimeStart,
T.TimeEnd

Getting the newest record from a database Multiple queries

I have a mysql database with vehicles records. I need a fast query that will return the newest records of those records that were updated within the last 4 minutes. For example vehicle "A" may be updated several times a minute so it will appear many times within the last 4min. Same with vehicle B C etc. I need only the most recent entries for each vehicle within a 4 min window. I have tried like this
SELECT *
FROM yourtable AS a
WHERE a.ts =
(SELECT MAX(ts)
FROM yourtable AS b
WHERE b.ts > NOW() - INTERVAL 5 MINUTE
AND b.name = a.name)
but it takes too long to produce results >10seconds.
Does this work?
select distinct a.id from yourtable AS a
where a.ts > NOW() - INTERVAL 5 MINUTE;
It gives all vehicles that were updated in last 4/5 minutes.
Thanks,
Rakesh