I have got a table with the following syntax:
ID, VALUE, TIMESTAMP
(ID,TIMESTAMP) is primary key, so there might be more than one row for each ID. There are 5000 unique ids.
I want to retrieve the most recent entry for each ID.
My naive way to do was:
SELECT * FROM table ORDER BY TIMESTAMP DESC LIMIT 5000;
For most cases this will give the correct result, but it is not guaranteed.
Because there might be 100k to 500k entries in the Table I would like to take performance into account.
What do you suggest?
TRY THIS
SELECT ID, VALUE, TIMESTAMP
FROM table
GROUP BY ID
HAVING MAX(TIMESTAMP)
ORDER BY TIMESTAMP DESC ;
OR
SELECT ID, VALUE, TIMESTAMP
FROM table
GROUP BY ID
ORDER BY TIMESTAMP DESC ;
Please try this :
SELECT * FROM
(SELECT ID,
VALUE,
ROW_NUMBER() OVER(PARTITION BY ID ORDER BY TIMESTAMP DESC) AS TIMESTAMP
FROM
TABLE )
WHERE TIMESTAMP=1 ;
If your DB supports QUALIFY statement you can try below also :
SELECT * FROM
TABLE
QUALIFY ROW_NUMBER() OVER(PARTITION BY ID ORDER BY TIMESTAMP DESC)=1 ;`enter code here`
You would find the latest date for each ID entry, try this
SELECT *
FROM table AS a
WHERE TIMESTAMP = (
SELECT MAX(TIMESTAMP)
FROM table AS b
WHERE a.ID = b.ID
)
Related
I want to fetch the latest entry to the database
I have this data
When I run this query
select id, parent_id, amount, max(created_at) from table group by parent_id
it correctly returns the latest entry but not the rest of the column
what I want is
how do I achieve that?
Sorry that I posted image instead of table, the table won't work for some reason
You can fetch the desired output using subquery. In the subquery fetch the max created_at of each parent_id which will return the row with max created_at for each parent_id. Please try the below query.
SELECT * FROM yourtable t WHERE t.created_at =
(SELECT MAX(created_at) FROM yourtable WHERE parent_id = t.parent_id);
If the id column in your table is AUTO_INCREMENT field then you can fetch the latest entry with the help of id column too.
SELECT * FROM yourtable t WHERE t.id =
(SELECT MAX(id) FROM yourtable WHERE parent_id = t.parent_id);
That's a good use case for a window function like RANK as a subquery:
SELECT id, parent_id, amount, created_at
FROM (
SELECT id, parent_id, amount, created_at,
RANK() OVER (PARTITION BY parent_id ORDER BY created_at DESC) parentID_rank
FROM yourtable) groupedData
WHERE parentID_rank = 1;
or with ORDER BY clause for the outer query if necessary:
SELECT id, parent_id, amount, created_at
FROM (
SELECT id, parent_id, amount, created_at,
RANK() OVER (PARTITION BY parent_id ORDER BY created_at DESC) parentID_rank
FROM yourtable) groupedData
WHERE parentID_rank = 1
ORDER BY id;
To explain the intention:
The PARTITION BY clause groups your data by the parent_id.
The ORDER BY clause sorts it starting with the latest date.
The WHERE clause just takes the entry with the latest date per parent id only.
The main point here is that your query is invalid. The DBMS should raise an error, but you work in a cheat mode that MySQL offers that allows you to write such queries without being warned.
My advice: When working in MySQL make sure you have always
SET sql_mode = 'ONLY_FULL_GROUP_BY';
As to the query: You are using MAX. Thus you aggregate your data. In your GROUP BY clause you say you want one result row per parent_id. You select the parent_id's maximum created_at. You also select the parent_id's ID, the parent_id itself, and the parent_id's amount. The parent_id's ID??? Is there only one ID per parent_id in your table? The amount? Is there only one amount per parent_id in the table? You must tell the DBMS which ID to show and which amount. You haven't done so, and this makes your query invalid according to standard SQL.
You are running MySQL in cheat mode,however, and so MySQL silently applies ANY_VALUE to all non-aggregated columns. This is what your query is turned into internally:
select
any_value(id),
parent_id,
any_value(amount),
max(created_at)
from table
group by parent_id;
ANY_VALUE means the DBMS is free to pick the attribute from whatever row it likes; you don't care.
What you want instead is not to aggregate your rows, but to filter them. You want to select only those rows with the maximum created_at per parent_id.
There exist several ways to get this result. Here are some options.
Get the maximum created_at per parent_id. Then select the matching rows:
select *
from table
where (parent_id, created_at) in
(
select parent_id, max(created_at)
from table
group by parent_id
);
Select the rows for which no newer created_at exists for the parent_id:
select *
from table t
where not exists
(
select null
from table newer
where newer.parent_id = t.parent_id
and newer.created_at > t.created_at
);
Get the maximum created_at on-the-fly. Then compare the dates:
select id, parent_id, amount, created_at
from
(
select t.*, max(created_at) over (partition by parent_id) as max_created_at
from table t
) with_max_created_at
where created_at = max_created_at;
select id, parent_id, amount, max(created_at)
from table
group by parent_id
order by max(created_at) desc
limit 1
UPDATE Here's a sqlfiddle http://sqlfiddle.com/#!2/e0822/1/0
I have a MySQL database of apps (itunes_id), each app id has a comments field. To preserve a history, every time a comment is changed, a new row of data is added. In the query below, I just want a list of the latest entry (highest id) of every app (itunes_id).
Here are the headers of my db:
id (key and auto increment)
itunes_id
comments
date
This query is getting the latest entry for a given itunes_id. How can I make this query more efficient?
SELECT * FROM (
SELECT * FROM (
SELECT * FROM Apps
ORDER BY id DESC
) AS apps1
GROUP BY itunes_id
) AS apps2
LIMIT 0 , 25
This query uses a subquery which separately gets the maximum ID for every itunes_ID. The result of the subquery is then join back on the original table provided that it matches on two columns: itunes_ID and ID.
SELECT a.*
FROM Apps a
INNER JOIN
(
SELECT itunes_id, MAX(ID) max_id
FROM Apps
GROUP BY itunes_id
) b ON a.itunes_id = b.itunes_id AND
a.ID = b.max_ID
LIMIT 0, 25
For faster performance, create a compound column INDEX on columns itunes_ID and ID. EG,
ALTER TABLE Apps ADD INDEX (itunes_ID, ID)
For a similar approach, I use a "recent" boolean field to mark records containing the latest version. This requires an UPDATE query on every insert (deactivate the previous recent record), but allows for a quick select query. Alternatively, you could maintain two tables, one with the recent records, the other one with the history for each app.
EDIT: Maybe you can try a table similar to this:
id int not null auto_increment primary key
version int not null
main_id int null
recent boolean not null
app varchar(32) not null
comment varchar(200) null
You can use the column "main_id" to point to the record with version 1.
SELECT * FROM (
SELECT * FROM (
SELECT * FROM Apps
ORDER BY id DESC
) AS apps1
GROUP BY itunes_id
) AS apps2
LIMIT 0 , 25
will not select the oldest record (you cannot assume the generated key will always be the "oldest"). What you want is something like this:
SELECT * FROM (
SELECT * FROM (
SELECT * FROM Apps
where some_date = (select max(some_date) from Apps limit 1)
ORDER BY id DESC
) AS apps1
GROUP BY itunes_id
) AS apps2
LIMIT 0 , 25
I just want the latest entry (highest id) for a given app (itunes_id)
This will do it
SELECT MAX(id), comments FROM Apps WHERE itunes_id = "iid";
or
SELECT id, comments FROM Apps WHERE itunes_id = "iid" ORDER BY id DESC LIMIT 1;
Where iid is the itunes id for which you want the latest comment.
Make sure id and itunes_id are indexed in a composite index for maximum efficiency.
I have a mySQl db (name "stocks") with 50 tables, each tables with
id, symbol, date, time, open, high, low, close, volume as columns (9 columns).
I would like to know what is the last record for each table, ordered for date then time.
Should I have to ORDER BY all data for each table or there is a better way to just know last record?
I am asking help for a query that just return only last record for each table in db.
Thanks
PS For last record I mean most recent as Date then Time
There are two options how to do that:
-- I would use this only if you need more than one records
SELECT * FROM table ORDER BY date DESC LIMIT 1;
-- Way to go:
SELECT * FROM table WHERE date = (SELECT MAX(date) FROM table) LIMIT 1;
Don't forget to add index on date. If it's possible you add lot's of records at the same time you will have to add:
ORDER BY id DESC -- In case that date is highest for records for last records
ORDER BY time DESC -- Every other case
To the end of query
I am going to make the assumption that the record with the largest ID is the "last" (assuming strictly increasing sequential IDs that are unique within a table). If you have a better definition of "last" that could make a difference.
To get one "last" record, you could do:
Select * from table_1 where id = (select max(id) from table_1);
To get the results of all 50 tables into a single result set, you could do:
Select * from table_1 where id = (select max(id) from table_1)
union
Select * from table_2 where id = (select max(id) from table_2)
union
Select * from table_3 where id = (select max(id) from table_3)
union...
A MySQL-specific solution could be
Select * from table_1 order by id desc limit 1
union
Select * from table_2 order by id desc limit 1
union
Select * from table_3 order by id desc limit 1
union...
Based on your edit (where you actually define what you mean by "last"):
Select * from table_1 order by date desc, time desc, id desc limit 1
union
Select * from table_2 order by date desc, time desc, id desc limit 1
union
Select * from table_3 order by date desc, time desc, id desc limit 1
union...
Here is one way to do it without sorting the table:
select * from tab1
where time = (select max(time)
from tab1
where date = (select max(date) from tab1))
and date = (select max(date) from tab1)
It should be very fast, like, O(c), provided that both columns are indexed, otherwise the time will simply be O(n)
How would I do something like this?
SQL SELECT row FROM table WHERE id=max(id)
You could use a subselect:
SELECT row
FROM table
WHERE id=(
SELECT max(id) FROM table
)
Note that if the value of max(id) is not unique, multiple rows are returned.
If you only want one such row, use #MichaelMior's answer,
SELECT row from table ORDER BY id DESC LIMIT 1
You could also do
SELECT row FROM table ORDER BY id DESC LIMIT 1;
This will sort rows by their ID in descending order and return the first row. This is the same as returning the row with the maximum ID. This of course assumes that id is unique among all rows. Otherwise there could be multiple rows with the maximum value for id and you'll only get one.
SELECT *
FROM table
WHERE id = (SELECT MAX(id) FROM TABLE)
You can not give order by because order by does a "full scan" on a table.
The following query is better:
SELECT * FROM table WHERE id = (SELECT MAX(id) FROM table);
One can always go for analytical functions as well which will give you more control
select tmp.row from ( select row, rank() over(partition by id order by id desc ) as rnk from table) tmp where tmp.rnk=1
If you face issue with rank() function depending on the type of data then one can choose from row_number() or dense_rank() too.
Try with this
SELECT top 1 id, Col2, row_number() over (order by id desc) FROM Table
How can I select the row with the highest ID in MySQL? This is my current code:
SELECT * FROM permlog WHERE max(id)
Errors come up, can someone help me?
SELECT * FROM permlog ORDER BY id DESC LIMIT 0, 1
if it's just the highest ID you want. and ID is unique/auto_increment:
SELECT MAX(ID) FROM tablename
For MySQL:
SELECT *
FROM permlog
ORDER BY id DESC
LIMIT 1
You want to sort the rows from highest to lowest id, hence the ORDER BY id DESC. Then you just want the first one so LIMIT 1:
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement.
[...]
With one argument, the value specifies the number of rows to return from the beginning of the result set
SELECT *
FROM permlog
WHERE id = ( SELECT MAX(id) FROM permlog ) ;
This would return all rows with highest id, in case id column is not constrained to be unique.
SELECT MAX(id) FROM TABLENAME
This identifies the largest id and returns the value
Suppose you have mulitple record for same date or leave_type but different id and you want the maximum no of id for same date or leave_type as i also sucked with this issue,
so Yes you can do it with the following query:
select * from tabel_name where employee_no='123' and id=(
select max(id) from table_name where employee_no='123' and leave_type='5'
)
SELECT MAX(ID) FROM tablename LIMIT 1
Use this query to find the highest ID in the MySQL table.
Since both SELECT MAX(id) FROM table and SELECT id FROM table ORDER BY id DESC LIMIT 0,1 fulfill the goal, the interesting part is, which performs better.
SELECT MAX(id) FROM table: 152ms
SELECT id FROM table ORDER BY id DESC LIMIT 0,1: 25ms
(InnoDB-table with 55M rows on MySQL 8.0, 10 runs, average result)
Of course thats not representive, but gives an idea, that the ORDER BY method performs significantly better.
This is the only proposed method who actually selects the whole row, not only the max(id) field. It uses a subquery
SELECT * FROM permlog WHERE id = ( SELECT MAX( id ) FROM permlog )
SELECT * FROM `permlog` as one
RIGHT JOIN (SELECT MAX(id) as max_id FROM `permlog`) as two
ON one.id = two.max_id