从汇率表隐式计算SQL中的汇率

时间:2018-07-02 12:53:35

标签: sql oracle currency-exchange-rates

我有一个数据表,其中的收入以多种货币表示(我们将此称为TRANSACTION_TABLE,其列如下:

TRANSACTION_NAME
TRANSACTION_VALUE
CURRENCY

,以及另一个带有汇率(EXCHANGE_RATE)的表,其列如下:

FROM_CURRENCY (e.g. JPY)
TO_CURRENCY (e.g. USD)
EXCHANGE_RATE (x)

该表至少具有将每种货币转换为美元的功能,但是对于非美元TO_CURRENCY值的汇率,它并不详尽。

我要实现的查询是一种将交易转换为任何货币的查询,即使未在EXCHANGE_RATE表中明确规定,也可以先将货币转换为USD,然后再从USD转换为目标货币。

例如1000 JPY为GBP:

  1. 查找日元到美元的汇率-计算= 1000 * EXCHANGE_RATE = 9
  2. 查找英镑对美元的汇率-计算= 9 \ EXCHANGE_RATE = 7

目前,我在TRANSACTION_TABLE上完成了EXCHANGE_RATE的左联接,但是我迷失了下一步。

任何帮助将不胜感激。

到目前为止,我构建的查询(非常基本)如下,并且我是SQL的新手。我首先构建此查询以将其转换为美元,但效果很好(因为我的汇率表包含所有货币的美元值),但是将目标货币设置为GBP时,它显然会失败,因为它只会返回空值。

SELECT TRANSACTION_NAME,
             SUM (TRANSACTION_VALUE * EXCHANGE_RATE)
                 AS "REVENUE GBP"
        FROM TRANSACTION_TABLE S
             LEFT JOIN EXCHANGE_RATE C ON S.CURRENCY = C.FROM_CURRENCY AND C.TO_CURRENCY = 'GBP'
ORDER BY TRANSACTION_NAME

2 个答案:

答案 0 :(得分:3)

如果您的EXCHANGE_RATE表已用完美元,那么您进行转换的“跳数”将不会超过两个。最多,您将转换为USD,然后再从USD转换为任何货币。鉴于此,我只会为所有可能的情况编写代码,而不要尝试像CONNECT BY这样的花哨的东西。

我认为“所有可能的情况”是:

  • 交易已使用目标货币
  • 交易使用可直接转换为目标货币的货币
  • 交易必须先转换为美元,然后再从美元转换为目标货币。

这是将执行此操作的查询。 WITH子句只是为了提供一些数据-它们不会成为您解决方案的一部分,因为您有实际的表。

WITH rates ( from_currency, to_currency, exchange_rate ) AS 
( SELECT 'JPY', 'USD', 0.009 FROM DUAL UNION ALL
  SELECT 'GBP', 'USD', 1.31 FROM DUAL UNION ALL
  SELECT 'CNY', 'USD', 0.15 FROM DUAL UNION ALL
  SELECT 'JPY', 'CNY', 0.06 FROM DUAL),
txns ( transaction_name, transaction_value, currency ) AS
 ( SELECT 'txn 1 in JPY', 1000, 'JPY' FROM DUAL UNION ALL
   SELECT 'txn 2 in GBP', 1000, 'GBP' FROM DUAL UNION ALL
   SELECT 'txn 3 IN CNY', 1000, 'CNY' FROM DUAL UNION ALL
   SELECT 'txn 4 IN unknown', 1000, 'XXX' FROM DUAL),
params ( target_currency ) AS 
 ( SELECT 'CNY' FROM DUAL )
SELECT t.transaction_name,
       t.transaction_value base_value,
       t.currency base_currency,
       t.transaction_value * CASE WHEN t.currency = params.target_currency THEN 1
            WHEN r1.from_currency IS NOT NULL THEN r1.exchange_rate
            ELSE r2usd.exchange_rate / r2tar.exchange_rate END converted_value,
        params.target_currency converted_currency
FROM   params CROSS JOIN 
       txns t 
       LEFT JOIN rates r1 ON r1.from_currency = t.currency AND r1.to_currency = params.target_currency
       LEFT JOIN rates r2usd ON r2usd.from_currency = t.currency AND r2usd.to_currency = 'USD'
       LEFT JOIN rates r2tar ON r2tar.from_currency = params.target_currency AND r2tar.to_currency = 'USD'

答案 1 :(得分:2)

我建议采取进一步措施,以 expand 交换表,并使用 UDS 作为转移货币来定义额外的汇率。

此查询添加通过USD计算的新汇率。这是一个受限制的简单内部联接,因此计算是通过“ USD”进行的,而从和到货币则不同。 WHERE子句限制了已经知道的组合。

select  er1.FROM_CURRENCY, er2.TO_CURRENCY,  er1.EXCHANGE_RATE * er2.EXCHANGE_RATE EXCHANGE_RATE
from exchange_rates er1
join exchange_rates er2
on er1.TO_CURRENCY = 'USD' and er2.FROM_CURRENCY = 'USD'  and er1.FROM_CURRENCY != er2.TO_CURRENCY
where (er1.FROM_CURRENCY, er2.TO_CURRENCY)
not in (select FROM_CURRENCY,   TO_CURRENCY from exchange_rates)

您可以定义一个物理新表或视图,甚至仅作为子查询执行它,作为原始表的UNION ALL和该查询的结果。

您的最终查询使用此扩展汇率表,而不是原始汇率表。

这是我测试过的样本数据

create table exchange_rates
as
select 'GBP' FROM_CURRENCY,  'USD' TO_CURRENCY, 1.31  EXCHANGE_RATE from dual union all
select 'EUR' FROM_CURRENCY,  'USD' TO_CURRENCY, 1.16 EXCHANGE_RATE from dual union all
select 'AUD' FROM_CURRENCY,  'USD' TO_CURRENCY, .73 EXCHANGE_RATE from dual union all
select 'USD' FROM_CURRENCY,  'GBP' TO_CURRENCY, .76  EXCHANGE_RATE from dual union all
select 'USD' FROM_CURRENCY,  'EUR' TO_CURRENCY, .86 EXCHANGE_RATE from dual union all
select 'USD' FROM_CURRENCY,  'AUD' TO_CURRENCY, 1.36 EXCHANGE_RATE from dual union all
select 'GBP' FROM_CURRENCY,  'EUR' TO_CURRENCY, 1.12 EXCHANGE_RATE from dual;