Suppose that I have a database which contains the following columns:
VehicleID|timestamp|lat|lon|
I may have multiple times the same VehicleId but with a different timestamp. Thus VehicleId,Timestamp is the primary key.
Now I would like to have as a result the last N measurements per VehicleId or the first N measurements per vehicleId.
How I am able to list the last N tuples according to an ordering column (e.g. in our case timestamp) per VehicleId?
Example:
|VehicleId|Timestamp|
1|1
1|2
1|3
2|1
2|2
2|3
5|5
5|6
5|7
In MySQL, this is most easily done using variables:
select t.*
from (select t.*,
(#rn := if(#v = vehicle, #rn + 1,
if(#v := vehicle, 1, 1)
)
) as rn
from table t cross join
(select #v := -1, #rn := 0) params
order by VehicleId, timestamp desc
) t
where rn <= 3;
Related
Let's say there are millions of records in my_table.
Here is my query to extract rows with a specific name from list:
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4')
How do I limit the returned result per name1, name2, etc?
The following query would limit the whole result (to 100).
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4') LIMIT 100
I need to limit to 100 for each name.
This is a bit of a pain in MySQL, but the best method is probably variables:
select t.*
from (select t.*,
(#rn := if(#n = name, #rn + 1,
if(#n := name, 1, 1)
)
) as rn
from my_table t cross join
(select #n := '', #rn := 0) params
order by name
) t
where rn <= 100;
If you want to limit this to a subset of the names, then add the where clause to the subquery.
Note: If you want to pick certain rows -- such as the oldest or newest or biggest or tallest -- just add a second key to the order by in the subquery.
Try
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4') FETCH FIRST 100 ROWS ONLY
Consider a table with the following columns:
Customer Email ID
Payment Method (COD/ Netbanking/ CreditCard/ DebitCard)
Order ID
Order Creation Date
Order Status(Success/ Failed/ Cancelled)
How do I fetch the last three successful orders past 3 months for each customer from these table in SQL along with the relevant details?
This is a bit painful in MySQL. Probably the simplest method is to use variables.
Your column names are not clear. And you have some additional conditions, but this is the basic idea:
select t.*
from (select t.*,
(#rn := if(#c = customerid, #rn + 1,
if(#c := customerid, 1, 1)
)
) as rn
from t cross join
(select #rn := 0, #c := '') params
order by customerid, orderdate desc
) t
where rn <= 3;
You can add the additional where conditions to the subquery.
I Hope this helps
SELECT *
FROM TABLENAME
WHERE OrderStatus='Success'
ORDER BY OrderCreationDate DESC
LIMIT 3;
I have the table with data:
And for this table I need to create pegination by productId column. I know about LIMIT N,M, but it works with rows and not with groups. For examle for my table with pegination = 2 I expect to retrieve all 9 records with productId = 1 and 2 (the number of groups is 2).
So how to create pegination by numbers of groups ?
I will be very thankfull for answers with example.
One way to do pagination by groups is to assign a product sequence to the query. Using variables, this requires a subquery:
select t.*
from (select t.*,
(#rn := if(#p = productid, #rn + 1,
if(#rn := productid, 1, 1)
)
) as rn
from table t cross join
(select #rn := 0, #p := -1) vars
order by t.productid
) t
where rn between X and Y;
With an index on t(productid), you can also do this with a subquery. The condition can then go in a having clause:
select t.*,
(select count(distinct productid)
from t t2
where t2.productid <= t.productid)
) as pno
from t
having pno between X and Y;
Try this:
select * from
(select * from <your table> where <your condition> group by <with your group>)
LIMIT number;
I am collecting data from various remote sensors that send their data every so many seconds. I record the name of the remote sensor and the time difference since the last time I received data from that instrument. The data for each instrument comes in a random order and not at set intervals.
The table looks like:
id instname timediff
1 inst01 1000
2 inst02 1100
3 inst01 1210
4 inst03 900
etc.
The id column is auto incrementing.
What I am trying to do is get the average timediff for each instrument for the last 10 values of each instrument.
the closest I've got is:
SELECT
inst AS Instrument,
AVG(diff / 1000) AS Average
FROM
(SELECT
instname AS inst, timediff AS diff
FROM
log
WHERE
instname = 'Inst01'
ORDER BY id DESC
LIMIT 0 , 10) AS two
Obviously this only works for 1 instrument and I'm not convinced the limit is working properly either. I don't know the names of the instruments nor how many I'll be collecting data from.
How do I get the average timediff of the last 10 values for each instrument using SQL?
Somewhat painfully. I think the easiest way is to use variables. The following query enumerates the readings for each instrument:
select l.*,
(#rn := if(#i = instname, #rn + 1,
if(#i := instname, 1, 1)
)
) as rn
from log l cross join
(select #i := '', #rn := 0)
order by instname, id desc;
You can then use this as a subquery to do your calculation:
select instname, avg(timediff)
from (select l.*,
(#rn := if(#i = instname, #rn + 1,
if(#i := instname, 1, 1)
)
) as rn
from log l cross join
(select #i := '', #rn := 0)
order by instname, id desc
) l
where rn <= 10
group by instname;
try using this:tested on less data but should work.
SELECT
inst AS Instrument,
diff AS Average
FROM
(SELECT
t1.instname AS inst,AVG(t1.timediff / 1000) AS diff
FROM
inst t1,inst t2
WHERE
t1.instname = t2.instname group by t1.instname ORDER BY t2.id DESC
LIMIT 0,10
) AS two
I have a MySQL table for fictional fitness app.
Let's say that app is monitoring user progress on doing pushups day by day.
TrainingDays
id | id_user | date | number_of_pushups
Now, I need to find if user have ever managed to do more than 100 pushups 5 days in a row.
I know this is probably doable by fetching all days and then making some php loops, but I wonder if there is possibility to do this in plain mysql...
In MySQL, the easiest way is to use variables. The following gets all sequences of days with 100 or more pushups:
select grp, count(*) as numdaysinarow
from (select (date - interval rn day) as grp, td.*
from (select td.*,
(#rn := if(#i = id_user, #rn + 1
if(#i := id_user, 1, 1)
) as rn
from trainingdays td cross join
(select #rn := 0, #i := NULL) vars
where number_of_pushups >= 100
order by id_user, date
) td
) td
group by grp;
This uses the observation that when you subtract a sequence of numbers from a series of dates that increment, then the resulting value is constant.
To determine if there are 5 or more days in a row, use max():
select max(numdaysinarow)
from (select grp, count(*) as numdaysinarow
from (select (date - interval rn day) as grp, td.*
from (select td.*,
(#rn := if(#i = id_user, #rn + 1
if(#i := id_user, 1, 1)
) as rn
from trainingdays td cross join
(select #rn := 0, #i := NULL) vars
where number_of_pushups >= 100
order by id_user, date
) td
) td
group by grp
) td;
Your app can then check the value against whatever minimum you like.
Note: this assumes that there is only one record per day. The above can easily be modified if you are looking for the sum of the number of pushups on each day.
Order of records shouldn't be relied on, e.g. with ORDER BY you can change the sequence.
However, you have many functions at hand in a database, which also enables you to use less PHP. What you want is SUM function. Combined with a WHERE clause, this should get you started:
SELECT SUM(number_of_pushups) AS sum_pushups
FROM TrainingDays
WHERE date >= :start_day
AND user_id = :user_id