我使用的汇率数据库的价值仅在特定日期有效。例如,如果我想将美元兑换成欧元,我必须使用特定日期内的特定汇率。汇率随着时间的推移而变化,最终会被另一个更新的汇率所取代。以下是我的汇率数据库样本:
Exchange_Rate_History
Valid-From Exchange-rate From-Currency To-Currency
2012-04-16 0.8 USD EUR
2012-04-18 0.82 USD EUR
2012-04-20 0.81 USD EUR
现在,如果您注意到,我只有一个'Valid-From'日期,但我没有'Valid-To'日期。
现在我有另一个需要加入Exchange_Rate_History表的表。此表包含购物交易
Purchases
Transaction-ID Transaction-Date Amount-In-USD
1 2012-04-16 100
2 2012-04-17 100
对于上述两笔交易,我们有两个不同的日期,即2012年4月16日和17日。但是对于这两个日期,我们需要使用标记为有效的汇率 - 来自2012-04-16。由于我只有一个约会,我不能使用BETWEEN..AND来执行连接。因此,无法进行以下连接
SELECT
*
FROM
Exchange_Rate_History
INNER JOIN Purchases ON (Purchases.Transaction-Date BETWEEN Exchange_Rate_History.Valid-From AND Exchange_Rate_History.???)
我正在考虑对Exchange_Rate_History表进行自连接(递归/自引用关系),这样我就会得到两个彼此相邻的Valid-From列。第一个Valid-From将是原始的,而第二个将是垂直移位的。结果表如下所示:
Exchange_Rate_History
Valid-From Exchange-rate From-Currency To-Currency Valid-From-1 (aliased to Valid-To)
2012-04-16 0.8 USD EUR 2012-04-18
2012-04-18 0.82 USD EUR 2012-04-20
2012-04-20 0.81 USD EUR
我想使用Valid-From-1字段,就像它是Valid-To字段一样,这样我就可以执行上面的SQL语句了。现在请注意,Valid-From字段的日期为4月16日,而Valid-To的日期为4月18日。但是在这个阶段我不知道如何做垂直“移动”记录的递归关系!
请帮忙吗?这不是一件容易的事!
答案 0 :(得分:1)
假设每个汇率从valid-from
开始有效,到下一个汇率开始时结束,
您想要选择早于交易日期的最新valid-from
。那将是当时最新的那一行。
您可以直接获取具有子查询的交易的汇率,如下所示。假设变量@currencyFrom
,@currencyTo
和@transactionDate
:
select top 1
exchange-rate
from Exchange_Rate_History erh
where erh.currency-from = @currencyFrom
and erh.currency-to = @currencyTo
and erh.valid-from < @transactionDate
order by erh.valid-from desc
您可以将其放在子查询中,以通过将外部字段名称替换为变量来获取事务的速率。
例如:
Select p.Transaction-ID, p.Transaction-Date, p.Amount-in-USD,
(select top 1
exchange-rate
from Exchange_Rate_History erh
where erh.currency-from = 'USD'
and erh.currency-to = 'CHF'
and erh.valid-from < p.Transaction-Date
order by erh.valid-from desc) as exchange-rate,
(select top 1
exchange-rate
from Exchange_Rate_History erh
where erh.currency-from = 'USD'
and erh.currency-to = 'CHF'
and erh.valid-from < p.Transaction-Date
order by erh.valid-from desc) * p.Amount-In-USD as Amount-In-CHF
from Purchases p
即使您正在进行两个子查询,您可能会发现它的表现也很好。你可以重写它以避免这种情况,但它可能不值得努力。
无法避免循环连接,但您的聚集索引应该在currency-from
,currency-to
,valid-from
上,然后它应该执行正常。如果您无法更改clusttered索引,请在这些字段上创建idex并在索引中包含exchange-rate
- 这也将提供良好的性能。
答案 1 :(得分:1)
CREATE FUNCTION GetExchangeRate
(
@TransactionDate DATETIME,
@FromCurrency VARCHAR(3),
@ToCurrency VARCHAR(3)
)
RETURNS TABLE
AS
RETURN
SELECT TOP 1
Rate
FROM
ExchangeRates
WHERE
FromCurrency = @fromCurrency
AND ToCurrency = @toCurrency
AND ValidFrom <= @transactionDate
ORDER BY
ValidFrom DESC
然后:
SELECT
Purchases.ID,
Purchases.Transaction-Date,
Purchases.Amount-In-USD,
ExchangeRate.Rate,
Purchases.Amount-In-USD * ExchangeRate.Rate As ConvertedAmount
FROM
Purchases
CROSS APPLY dbo.GetExchangeRate(Purchases.Transaction-Date, 'USD', 'EUR') ExchangeRate
答案 2 :(得分:0)
以下情况如何?
SELECT *
, (SELECT TOP 1 Valid-From
FROM Exchange_Rate_History ex2
WHERE ex2.From-Currency = ex1.From-Currency
AND ex2.To-Currency = ex1.To-Currency
AND ex2.Valid-From > ex1.Valid-From
ORDER BY ex2.Valid-From ASC) Valid-To
FROM Exchange_Rate_History ex1
关于如何处理它可能还有很多其他选项,但这是一个简单的子查询方法。
方法2:
使用交叉应用可能会提高效率。
SELECT *
FROM Exchange_Rate_History ex1
CROSS APPLY (SELECT TOP 1 Valid-From
FROM Exchange_Rate_History ex2
WHERE ex2.From-Currency = ex1.From-Currency
AND ex2.To-Currency = ex1.To-Currency
AND ex2.Valid-From > ex1.Valid-From
ORDER BY ex2.Valid-From ASC) Valid-To
答案 3 :(得分:0)
窗口函数可以使用lag()和lead()函数:
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path='tmp';
CREATE TABLE exchange
( valid_from DATE NOT NULL
, cur_from CHAR(3)
, cur_to CHAR(3)
, rate FLOAT
,PRIMARY KEY(cur_from,cur_to,valid_from)
);
INSERT INTO exchange(valid_from,rate,cur_from,cur_to) VALUES
('2012-04-16', 0.8, 'USD', 'EUR' )
, ('2012-04-18', 0.82, 'USD', 'EUR' )
, ('2012-04-20', 0.81, 'USD', 'EUR' )
, ('2012-04-16', 800, 'USD', 'YEN' )
, ('2012-04-18', 820, 'USD', 'YEN' )
, ('2012-04-20', 810, 'USD', 'YEN' )
;
WITH next AS (
SELECT valid_from
, lead (valid_from) OVER nxt AS valid_to
, cur_from
, cur_to
, rate
FROM exchange
WINDOW nxt AS (
PARTITION BY cur_from,cur_to
ORDER BY cur_from,cur_to,valid_from)
)
SELECT * from next
;
结果:
NOTICE: drop cascades to table tmp.exchange
DROP SCHEMA
CREATE SCHEMA
SET
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "exchange_pkey" for table "exchange"
CREATE TABLE
INSERT 0 6
valid_from | valid_to | cur_from | cur_to | rate
------------+------------+----------+--------+------
2012-04-16 | 2012-04-18 | USD | EUR | 0.8
2012-04-18 | 2012-04-20 | USD | EUR | 0.82
2012-04-20 | | USD | EUR | 0.81
2012-04-16 | 2012-04-18 | USD | YEN | 800
2012-04-18 | 2012-04-20 | USD | YEN | 820
2012-04-20 | | USD | YEN | 810
(6 rows)
(更新:添加日元和PARTITION BY)