Reputation: 128
please help me with the following problem. I have spent already one week trying to put all the logic into one SQL query but still got no elegant result. I hope the SQL experts could give me a hint,
I have a table which has 4 fields: date, expire_month, expire_year and value. The primary key is defined on 3 first fields. Thus for a concrete date few values are present with different expire_month, expire_year. I need to chose one value from them for every date, present in the table.
For example, when I execute a query:
SELECT date, expire_month, expire_year, value FROM futures
WHERE date = ‘1989-12-01' ORDER BY expire_year, expire_month;
I get a list of values for the same date sorted by expirity (months are coded with letters):
1989-12-01 Z 1989 408.25
1989-12-01 H 1990 408.25
1989-12-01 K 1990 389
1989-12-01 N 1990 359.75
1989-12-01 U 1990 364.5
1989-12-01 Z 1990 375
The correct single value for that date is the k-th record from top. For example, of k is 2 then the «correct single» record would be:
1989-12-01 H 1990 408.25
How can I select these «correct single» values for every date in my table?
Upvotes: 0
Views: 311
Reputation: 52579
While forpas's answer is the better one (Though I think I'd use row_number()
instead of rank()
here), window functions are fairly recent additions to Sqlite (In 3.25). If you're stuck on an old version and can't upgrade, here's an alternative:
SELECT date, expire_month, expire_year, value
FROM futures AS f
WHERE (date, expire_month, expire_year) =
(SELECT f2.date, f2.expire_month, f2.expire_year
FROM futures AS f2
WHERE f.date = f2.date
ORDER BY f2.expire_year, f2.expire_month
LIMIT 1 OFFSET 1)
ORDER BY date;
The OFFSET
value is 1 less than the Kth row - so 1 for the second row, 2 for the third row, etc.
It executes a correlated subquery for every row in the table, though, which isn't ideal. Hopefully your composite primary key columns are in the order date, expire_year, expire_month
, which will help a lot by eliminating the need for additional sorting in it.
Upvotes: 1
Reputation: 41
You can try the following query.
select * from
(
SELECT rownum seq, date1, expire_month, expire_year, value FROM testtable
WHERE date1 = to_date('1989-12-01','yyyy-mm-dd')
ORDER BY expire_year, expire_month
)
where seq=2
Upvotes: -2
Reputation: 164184
You can do it with rank()
:
select t.date, t.expire_month, t.expire_year, t.value from (
select *,
rank() over(partition by date order by expire_year, expire_month) rn
from futures
) t
where t.rn = 2
The column rn
in the subquery, is actually the rank of the row grouped by date
.
Change 2
to the rank you want.
Upvotes: 2