Reputation: 3318
My table looks like this:
----------------------------------------------------------
| ID | League | Reference | Created_at | Value |
----------------------------------------------------------
| 1 | Test | Exa | 2018-08-05 11:52:30 | 12.00 |
----------------------------------------------------------
| 2 | Test | Alch | 2018-08-05 12:52:30 | 9.12 |
----------------------------------------------------------
| 3 | Test | Chrom | 2018-08-05 12:50:30 | 6.00 |
----------------------------------------------------------
| 4 | Test | Chrom | 2018-08-05 10:50:30 | 2.00 |
----------------------------------------------------------
Every 5 minutes I save a reference value on the table
I want to retrieve values of each reference (latest ones ordering by created_at DESC
. Currently on my code I just loop over an array of references [exa, alch, ...]
and execute the following query (for each league):
SELECT created_at, league, value, reference
FROM currency
WHERE league = ? AND reference = ?
ORDER BY created_at DESC
LIMIT 1
Basically I execute that query for each reference of each league, resulting in a lot of queries executed, and leading to high response times on my server...
The expected result should be, gather each reference value from X league, but only gather the latest inserted value (created_at DESC
), each reference type (exa, alch, ...) will have different created_at
values (may or not be equal to other reference types)
I tried using group_by
with no success at all since I will only get the first results (older ones) of the table:
SELECT created_at, league, value, reference
FROM currency
WHERE league = ? AND reference IN ('exa', 'alch', ...)
GROUP BY created_at DESC
I assume this group_by
approach would be faster since its one query for each league, but I always get older results instead of recently created ones...
Upvotes: 0
Views: 66
Reputation: 452
This query seems more efficient, you can chech the fiddle here: http://sqlfiddle.com/#!9/2b2dfe/8
If still have problems in production, review your indexes.
SELECT
currency.ID,
currency.League,
currency.Reference,
currency.Created_at,
currency.Value
FROM
currency
JOIN (
SELECT
League,
Reference,
MAX(Created_at) AS Created_at
FROM
currency
GROUP BY
League,
Reference
) AS a
ON
currency.League = a.League
AND currency.Reference = a.Reference
AND currency.Created_at = a.Created_at
Upvotes: 1
Reputation: 364
Try the following query-:
with cte as
(
select created_at, league, value, reference,ROW_NUMBER() over (partition by league,reference order by Created_at desc) rn
from currency
)select * from cte where rn=1
SQL Server
Upvotes: 1
Reputation: 50163
You can use subquery
with limit
clause :
select c.*
from currency c
where id = (select c1.id
from currency c1
where c1.league = c.league and
c1.Reference = c.Reference -- might be you need this also
order by c1.created_at desc
limit 1
);
Upvotes: 1
Reputation: 44766
Have a sub-query that returns each league's max created_at value. JOIN
with that result:
select c1.*
from currency c1
join (select league, max(created_at) max_created_at
from currency
group by league) c2
on c1.league = c2.league
and c1.created_at = c2.max_created_at
Upvotes: 1
Reputation: 1269773
Use filtering:
select c.*
from currency c
where c.created_at = (select max(c2.created_at)
from currency c2
where c2.league = c.league
);
Upvotes: 0