Reputation: 2952
I have a table of data which stores prices for different commodities on different dates.
CREATE TABLE COMMODITIES(
[MARKET_DATE] [datetime2](0) NOT NULL,
[THE_TYPE] [numeric](2, 0) NOT NULL,
[CLOSE_VALUE] [numeric](10, 4) NULL,
) ON [PRIMARY]
GO
MARKET_DATE
holds the trading date (the dates are in ascending order, but non-sequential)
CLOSE_VALUE
holds the price
THE_TYPE
holds the type of commodity.
The trading dates for each commodity are different.
I need to get a list of all dates where THE_TYPE
=1, with the price, as well as the corresponding price for the commodity with THE_TYPE
=2
If the trading dates for each commodity were the same I could do a simple join (equivalent to the Excel VLOOKUP (, false)
SELECT mr1.market_date
,mr1.close_value,mr2.close_value
FROM commodities mr1
LEFT JOIN commodities mr2 ON mr1.market_date = mr2.market_date
AND mr2.the_type = 2
WHERE mr1.the_type = 1
However because the trading dates are not the same, I need to look for the a non-exact match equivalent to the Excel VLOOKUP (, true)
- i.e. the maximum date in mr2
which is on or before mr1.market_date
I am looking for a neat solution. I could as a workaround enter the intervening dates into the database which would work. Or alternatively I could do the following
SELECT mr1.market_date
,mr1.close_value
,
(SELECT top 1 close_value
FROM commodities mr2
where mr2.market_date <= mr1.market_date
AND mr2.the_type = 2
order by market_date desc
) AS close_value
FROM commodities mr1
WHERE mr1.the_type = 1
but I hope there is a neater (and quicker) solution
As an example, if the table holds the following
MARKET_DATE CLOSE_VALUE THE_TYPE
2012-01-01 300 1
2012-01-03 310 1
2012-01-05 310 1
2012-01-01 400 2
2012-01-02 420 2
2012-01-05 430 2
I would get
2012-01-01 300 400
2012-01-03 310 420
2012-01-05 310 430
Upvotes: 3
Views: 3660
Reputation: 45106
WITH OrderedOrders AS
(
SELECT mr1.market_date
,mr1.close_value as mr1close
,mr2.close_value as mr2close
,ROW_NUMBER() OVER (PARTITION BY mr1.market_date ORDER BY mr2.market_date desc) AS RowNumber
FROM commodities mr1
JOIN commodities mr2
ON mr2.market_date <= mr1.market_date
AND mr2.the_type = 2
AND mr1.the_type = 1
)
SELECT market_date, mr1close, mr2close
FROM OrderedOrders
WHERE RowNumber = 1
Upvotes: 1
Reputation: 1538
You could use CROSS APPLY. It might be slightly faster but probably not noticeable for this case:
SELECT mr1.market_date
,mr1.close_value as close_value_1
,p.close_value as close_value_2
FROM commodities mr1
cross apply
(SELECT top 1 close_value
FROM commodities mr2
where mr2.market_date <= mr1.market_date
AND mr2.the_type = 2
order by market_date desc) p
WHERE mr1.the_type = 1
See it in action
Upvotes: 2