Getting all the rows between first timestamp and the difference between first and second - MySQL - mysql

I have a requirement to get all the records between the times of two sign-ins of the user.
When we retrieve the row of the first sign in and get the first timestamp (t1), we want to get all the hits made by the user between this and the second timestamp (t2).
What I am doing is: getting the first timestamp (t1) and subtracting it with the second timestamp (t2) of the user. I'll then add the difference (t2-t1) with the first timestamp and run query to get all the hits between t1 and (t1+d).
Hence there are two things I am trying to do: (Getting second timestamp and the difference)
first timestamp (t1) is: 1507559316
SELECT
id, timestamp, (timestamp - 1507559316) as Difference
FROM
login_activity l
WHERE
l.uid=445 AND timestamp > 1507559316
ORDER BY
timestamp
LIMIT 1
Getting all the rows between first timestamp and the Difference
t1 = 1507559316
difference = 1226
SELECT
name, address, time
FROM
records r
WHERE
time BETWEEN FROM_UNIXTIME(1507559316) AND FROM_UNIXTIME(1507559316 + 1226)
ORDER BY
time
Do you think it's the right way to approach this?

Unless I seriously have misunderstood something, your method is unnecessarily complicated. You seem to have A and B and then are re-computing B by doing A + (B - A). This is mysterious.
Assuming that your first timestamp is in t1, you could simplify the first query to
SELECT
id, timestamp AS t2
FROM
login_activity l
WHERE
l.uid=445 AND t2 > t1
ORDER BY
timestamp
LIMIT 1
and your second query to
SELECT
name, address, time
FROM
records r
WHERE
time BETWEEN FROM_UNIXTIME(t1) AND FROM_UNIXTIME(t2)
ORDER BY
time
There is no need to re-compute t2 as t1 + (t2 - t1) and thus no need to compute the difference in the first place.

Related

Selecting only one day bigger than given date in MySQL table

I have a table in MySQL database which is loaded like:
Now I need to select only one level of dates that are greater than or equal given data. For example if the given is 11/13/2019 I need to have only all rows that have 11/14/2019 like:
or if the given is 11/15/2019 returns only 11/16/2019 like
My dates are not always listed in sequence of real date format. As you can see there is gap between 11/14/2019 and 11/16/2019 and the 11/15/2019 is missing so I was not able to use the BETWEEN key in MySQL by adding a number to given on each select query.
I think you want:
select t.*
from t
where t.date = (select min(t2.date)
from t t2
where t2.date > ? -- the date you care about
);

MySQL, return all measurements and results within X last hours

This question is very much related to my previous question: MySQL, return all results within X last hours altough with additional significant constraint:
Now i have 2 tables, one for measurements and one for classified results for part of the measurements.
measurements are constantly arrive so as result, that are constantly added after classification of new measurements.
results will not necessarily be stored in the same order of measurement's arrive and store order!
I am interested only to present the last results. By last i mean to take the max time (the time is a part of the measurement structure) of last available result call it Y and a range of X seconds , and present the measurements together with the available results in the range beteen Y and Y-X.
The following are the structure of 2 tables:
event table:
CREATE TABLE `event_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`Feature` char(256) NOT NULL,
`UnixTimeStamp` int(10) unsigned NOT NULL,
`Value` double NOT NULL,
KEY `ix_filter` (`Feature`),
KEY `ix_time` (`UnixTimeStamp`),
KEY `id_index` (`id`)
) ENGINE=MyISAM
classified results table:
CREATE TABLE `event_results` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`level` enum('NORMAL','SUSPICIOUS') DEFAULT NULL,
`score` double DEFAULT NULL,
`eventId` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `eventId_index` (`eventId`)
) ENGINE=MyISAM
I can't query for the last measurements timestamp first since i want to present measurements for which there are currently results, and since measurements arrive constantly, results may still not be available.
Therefore i thought of joining the two tables using
event_results.eventId=event_data.id and than selecting the max time of event_data.UnixTimeStamp as maxTime , after i have the maxTime, i need to do the same opearation again (joining 2 tables) and adding in a where clause a condition
WHERE event_data.UnixTimeStamp >= maxTime + INTERVAL -X SECOND
It seems to be not efficient to execute 2 joins only to achieve what i am asking, Do you have more ef
From my understanding, you are using an aggregate function, MAX. This will produce a record set of size one as a result, which is the highest time from which you will perform. Therefore, it needs to be broken out into a sub query (As you say, nested select). You HAVE to do 2 queries at some point. (Your answer to the last question has 2 queries in it, by having subqueries/nested selects).
The main time sub queries cause problems is when you perform the subquery in the select part of the query, as it performs the subquery for each time there is a row, which will make the query run exponentially slower as the resultset grows. Lets take the answer to your last question and write it in a horrible, inefficient way:
SELECT timeStart,
(SELECT max(timeStart) FROM events) AS maxTime
FROM events
WHERE timeStart > (maxTime + INTERVAL -1 SECOND)
This will perform a select query for each time there is an eventTime record, for the max eventtime. It should produce the same result, but this is slow. This is where the fear of subqueries comes from.
It also performs the aggregate function MAX on each row, which will return the same answer each time. So, you perform that sub query ONCE rather than on each row.
However, in the case of the answer of your last question, the MAX sub query part is ran once, and used to filter on the where, of which that select is ran once. So, in total, 2 queries are ran.
2 super fast queries are faster ran one after the other than 1 super slow query that is super slow.
I'm not entirely sure what resultset you want returned, so I am going to make some assumptions. Please feel free to correct any assumptions I've made.
It sounds (to me) like you want ALL rows from event_data that are within an hour (or however many seconds) of the absolute "latest" timestamp, and along with those rows, you also want to return any related rows from event_results, if any matching rows are available.
If that's the case, then using an inline view to retrieve the maximum value of timestamp is the way to go. (That operation will be very efficient, since the query will be returning a single row, and it can be efficiently retrieved from an existing index.)
Since you want all rows from a specified period of time (from the "latest time" back to "latest time minus X seconds"), we can go ahead and calculate the starting timestamp of the period in that same query. Here we assume you want to "go back" one hour (=60*60 seconds):
SELECT MAX(UnixTimeStamp) - 3600 FROM event_data
NOTE: the expression in the SELECT list above is based on UnixTimeStamp column defined as integer type, rather than as a DATETIME or TIMESTAMP datatype. If the column were defined as DATETIME or TIMESTAMP datatype, we would likely express that with something like this:
SELECT MAX(mydatetime) + INTERVAL -3600 SECONDS
(We could specify the interval units in minutes, hours, etc.)
We can use the result from that query in another query. To do that in the same query text, we simply wrap that query in parentheses, and reference it as a rowsource, as if that query were an actual table. This allows us to get all the rows from event_data that are within in the specified time period, like this:
SELECT d.id
, d.Feature
, d.UnixTimeStamp
, d.Value
JOIN ( SELECT MAX(l.UnixTimeStamp) - 3600 AS from_unixtimestamp
FROM event_data l
) m
JOIN event_data d
ON d.UnixTimetamp >= m.from_unixtimestamp
In this particular case, there's no need for an upper bound predicate on UnixTimeStamp column in the outer query. This is because we already know there are no values of UnixTimeStamp that are greater than the MAX(UnixTimeStamp), which is the upper bound of the period we are interested in.
(We could add an expression to the SELECT list of the inline view, to return MAX(l.UnixTimeStamp) AS to_unixtimestamp, and then include a predicate like AND d.UnixTimeStamp <= m.to_unixtimestamp in the outer query, but that would be unnecessarily redundant.)
You also specified a requirement to return information from the event_results table.
I believe you said that you wanted any related rows that are "available". This suggests (to me) that if no matching row is "available" from event_results, you still want to return the row from the event_data table.
We can use a LEFT JOIN operation to get that to happen:
SELECT d.id
, d.Feature
, d.UnixTimeStamp
, d.Value
, r.id
, r.level
, r.score
, r.eventId
JOIN ( SELECT MAX(l.UnixTimeStamp) - 3600 AS from_unixtimestamp
FROM event_data l
) m
JOIN event_data d
ON d.UnixTimetamp >= m.from_unixtimestamp
LEFT
JOIN event_results r
ON r.eventId = d.id
Since there is no unique constraint on the eventID column in the event_results table, there is a possibility that more than one "matching" row from event_results will be found. Whenever that happens, the row from event_data table will be repeated, once for each matching row from event_results.
If there is no matching row from event_results, then the row from event_data will still be returned, but with the columns from the event_results table set to NULL.
For performance, remove any columns from the SELECT list that you don't need returned, and be judicious in your choice of expressions in an ORDER BY clause. (The addition of a covering index may improve performance.)
For the statement as written above, MySQL is likely to use the ix_time index on the event_data table, and the eventId_index index on the event_results table.

SQL MIN() selecting Data. ORDER table correctly

I have 2 questions. First of all I have a MySQL Database with the rows: id(AUTO_INCREMENT PRIMARY KEY), name and time. This database represents the times of a race. I would like to select the name and time where the time is the smallest.
SELECT name, MIN(time) as time FROM race GROUP BY TIME;
This query gives me all times and names as long as there are no duplicates in the names. I however only want the fastest time and the name in that row.
Then when I submit my time i would like to know on what place I am. Will ORDER BY TIME keep each ID of each row the same or can I just ORDER table BY time and then select row where ID= 1?
If it's possible to have multiple entries with the same time, I would use a nested query like this, because limiting the result set to 1 may exclude a name.
select name, time from race where time = (select min(time) from race)
If you want to know what place a given time is in, just count the number of entries that have times less than it.
select count(*) + 1 as place from race where time < [your time]
For your first question, what you want is to select the 'least' time.
Here is, what I think, the clearest way to do that, which uses the LIMIT function to only return 1 row.
MySQL:
SELECT name, time
FROM race
ORDER BY time asc
LIMIT 1;
MS SQL:
SELECT TOP 1 name, time
FROM race
ORDER BY time asc

Get the closest value from mysql table

This might be a simple one, but since I don't have much knowledge about MySQL I don't know how to do this, This is what I basically want,
I have a query like this
//time format "yyyy-MM-dd"
SELECT ID
FROM `id_table`
WHERE time > "2012-01-05 " AND time < "2012-01-10";
But in the id_table I have data only up to 2012-01-04 then it starts again from "2012-01-20", so above query would return null. Is there a any way where I can retrieve the last data record from the table, as for this example can I get the ID of 2012-01-04 date from the table when I query like this
SELECT ID
FROM `id_table`
WHERE time > "2012-01-05"
Are you looking for the one (i assume max ID) ID of the row with the nearest time to 2010-01-05?
SELECT MAX(ID) as LastId FROM id_table
WHERE time = (SELECT MAX(time)
FROM id_table WHERE time < '2012-01-05')
Try this:
SELECT ID FROM id_table
WHERE time between
least((select max(time) from id_table), "2012-01-05") AND "2012-01-10";
Note that between will get data from "2012-01-10" and ("2012-01-05" OR "2012-01-05)
To get the record closest to the given time ( you could easily tweak this if you care about dealing with duplicates, if that doesn't matter then this alone should suffice)
SELECT
ID
FROM
id_table
ORDER BY ABS(DATEDIFF(time, '2012-01-05'))
LIMIT 1
NOTE: If the time field is a time value yyyy-mm-dd hh:mm:ss then you can use TIMEDIFF for a more accurate comparison.
OP If you will explain more on how you would like to handle different cases I can tweak this example to suit them. Cheers.

mySQL select rows from a single table for each user_id which are close in timestamp

Not sure how best to word this, so please bear with me. My table (simplified) is as follows:
id - Integer - auto increment
user_id - Integer
timestamp - Datetime
What I need is the ability to query this table and select all records where the timestamp columns are within a predefined time range (potentially arbitrary, but lets say 10 minutes) for each user_id.So, for example, I would like to know if there is an entry for hypothetical user_id 5 at "2011-01-29 03:00:00" and then next at "2011-01-29 03:02:00" but not if a user searched once at "2011-01-29 03:00:00" and then next at "2011-01-29 05:00:00". This would also need to capture instances where a user searches more than 2 times, each within the time range of the previous.
For background, this is a table of site searches, and I would like to know all instances where a user searches for something, then searches again (presumably because their previous search did not provide the results they were looking for).
I know this is probably simpler than I am making it out to be, but I can't seem to figure it out. I can clarify or provide additional info if needed. Thanks!
EDIT:
I am interested in the search returning results for all of the users in the table, not just user #5, and also to search without input of the actual times. The timestamp should not be something which is manually input, but should instead should find rows by each user which are within 10 minutes of one another.
SELECT distinct t1.user_id, t1.another_field, t1.another_field
FROM
table t1,
table t2
WHERE
t1.user_id = t2.user_id
AND abs(timestampdiff(MINUTE, t1.timestamp, t2.timestamp)) < 10
if you want to further limit the results, you can add
AND t1.user_id = any_number (or IN or between, etc)
To restrict date range add,
AND t1.timestamp BETWEEN A and B (or > or <)
This should give you all users and theirs number of searches within time limit:
SELECT user_id, COUNT(*) AS cnt FROM table
WHERE timestamp BETWEEN "2011-01-29 03:00:00" AND "2011-01-29 03:02:00"
GROUP BY user_id
ORDER BY user_id
This will show you number of searches made just by user_id #5:
SELECT COUNT(*) AS cnt FROM table
WHERE user_id=5
AND timestamp BETWEEN "2011-01-29 03:00:00" AND "2011-01-29 03:02:00"
Depending on actual DB the syntax might be somewhat different, especially the format of dates passed to BETWEEN condition.