Możesz użyć row_number()
dwa razy:
select *
from (
select *
, row_number() over (partition by OT order by OI desc) as rn2
from (
select *
, row_number() over (partition by EI, BI, OT
order by created_at desc) as rn1
from Odds
where EI = 1 -- for event 1
) sub1
where rn1 = 1 -- Latest row per EI, BI, OT
) sub2
where rn2 = 1 -- Highest OI per OT
Ale jeśli stół będzie rósł, będzie to źle działać. Możesz dodać tabelę historii, taką jak OddsHistory, i przenieść tam nieaktualne kursy. Gdy w tabeli Kursy znajdują się tylko najnowsze kursy, zapytanie staje się znacznie prostsze.
Przykład na żywo w SQL Fiddle.