Reputation: 45752
SELECT M.TradeDate, M.Expiry, M.Future
FROM MTM as M
JOIN (SELECT TradeDate, MIN(Expiry) as Expiry
FROM MTM
WHERE Code = 'GOVI'
and Type = 'F'
GROUP BY TradeDate) as T
ON M.TradeDate = T.TradeDate and M.Expiry = T.Expiry
WHERE M.Code = 'GOVI'
and M.Type = 'F'
ORDER BY TradeDate
In this query, I want to extract a TradeDate, the nearest expiry (min) and the "Future" value that corresponds to that near expiry. This corresponding future means I now have to have a bloated nested query. The query does works perfectly. But I'm sure there must be a quicker (to develop, not necessarily to execute), clearer way to write it. Without the nested query and without repeating the exact same WHERE
conditions. I thought maybe OVER could help but I can't see how. Is this really the only way to do it?
SQL is normally so declarative but I feel that in this form of query, which I encounter often, the query really doesn't read like the request you make yourself in your head.
Upvotes: 1
Views: 58
Reputation: 280431
The self-join method is the old, expensive way to do it, and you'll find that its cost goes up exponentially as the table gets larger. Since 2005, we've been able to use window functions like ROW_NUMBER()
to return grouped results along with the non-grouped data in that row. Here is how I would write your query:
;WITH m AS
(
SELECT TradeDate, Expiry, Future, rn = ROW_NUMBER() OVER
(PARTITION BY TradeDate ORDER BY Expiry)
FROM dbo.MTM
WHERE Code = 'GOVI' AND Type = 'F'
)
SELECT TradeDate, Expiry, Future
FROM m
WHERE rn = 1
ORDER BY Expiry;
Basically, this takes each unique TradeDate and applies a "rank" to each set (from 1-n) based on the value of Expiry.
Upvotes: 1