2012-12-06 33 views
0

鉴于货币和汇率的元组,如下面的表格:如何产生汇率的所有可能的组合在SQL

EUR CHF 1.20 
USD EUR 0.80 
CHF JPY 1.30 

我怎么能简单地生成货币之间的所有汇率( A,B)还有(B,A)?

我想有以下几点:

EUR CHF 
CHF EUR 

EUR USD 
USD EUR 

USD CHF 
CHF USD 

与所有可能的组合,即利率可以从多个利率衍生通过链接他们

A to B * B to C * C to D = A to D 
+1

但据推测你需要计算两种货币之间的最短路径? – Jodrell

+1

并忽略EUR/EUR等? –

+0

问题的大小是可以忽略的,但当然最短会更好 – Edmondo1984

回答

1

您可以用Recursive Common Table Expression

设置做到这一点:

Create Table ExchangeRates (
    FromCurrency char(3), 
    ToCurrency char(3), 
    Rate decimal(10, 2), 
    Constraint PK_ExchangeRates Primary Key (FromCurrency, ToCurrency) 
); 

Create Index IX_ToCurrency On ExchangeRates(ToCurrency, FromCurrency, Rate); 

Insert Into ExchangeRates (FromCurrency, ToCurrency, Rate) Values 
    ('EUR', 'CHF', 1.20), 
    ('USD', 'EUR', 0.80), 
    ('CHF', 'JPY', 1.30); 

的CTE,它假定所有的货币代码是完全三个大字:

With AllExchanges as (
    Select 
     FromCurrency, 
     ToCurrency, 
     Rate 
    From 
     ExchangeRates 
    Union 
    Select 
     ToCurrency, 
     FromCurrency, 
     Cast(1.0/Rate As Decimal(10, 2)) 
    From 
     ExchangeRates 
) 
, Paths as (
    Select 
     FromCurrency, 
     cast(FromCurrency as varchar(max)) As ExchangePath, 
     ToCurrency, 
     Rate 
    From 
     AllExchanges a 
    Union All 
    Select 
     p.FromCurrency, 
     p.ExchangePath + ',' + p.ToCurrency, 
     a.ToCurrency, 
     Cast(p.Rate * a.Rate as Decimal(10, 2)) 
    From 
     Paths p 
      Inner Join 
     AllExchanges a 
      On p.ToCurrency = a.FromCurrency 
    Where 
     p.ExchangePath Not Like '%' + a.ToCurrency + '%' 
    ) 
Select 
    FromCurrency, 
    ExchangePath + ',' + ToCurrency As ExchangePath, 
    ToCurrency, 
    Rate 
From 
    Paths 

http://sqlfiddle.com/#!3/0fdc5

+0

美丽而优雅 – Edmondo1984

1

我能找到的唯一方法要做到这一点是使用循环,我所有的查询下面使用此示例数据:

DECLARE @T TABLE (FromCurrency VARCHAR(3), ToCurrency VARCHAR(3), ExchangeRate DECIMAL(10, 5)); 
INSERT @T VALUES 
    ('EUR', 'CHF', 1.20), 
    ('USD', 'EUR', 0.80), 
    ('CHF', 'JPY', 1.30); 

该fi第一步是获得所有的互惠汇率(即乙 - 从A的表> A - > B),因为这些是最容易得到:

DECLARE @TempExchangeRates TABLE (FromCurrency VARCHAR(3), ToCurrency VARCHAR(3), ExchangeRate DECIMAL(10, 5)); 

INSERT @TempExchangeRates (FromCurrency, ToCurrency, ExchangeRate) 
SELECT FromCurrency, ToCurrency, ExchangeRate 
FROM @T 
UNION 
SELECT ToCurrency, FromCurrency, CAST(1/ExchangeRate AS DECIMAL(10, 5)) 
FROM @T t 
WHERE NOT EXISTS 
     ( SELECT 1 
      FROM @T t2 
      WHERE t.FromCurrency = t2.ToCurrency 
      AND  t.ToCurrency = t2.FromCurrency 
     ) 

在这一点上,我们有:

CHF EUR 0.83333 
CHF JPY 1.30000 
EUR CHF 1.20000 
EUR USD 1.25000 
JPY CHF 0.76923 
USD EUR 0.80000 

所以我们还缺

CHF --> USD 
EUR --> JPY 
JPY --> CHF 
JPY --> EUR 
USD --> EUR 

你需要保持执行此加入

SELECT a.FromCurrency, b.ToCurrency, CAST(a.ExchangeRate * b.ExchangeRate AS DECIMAL(10, 5)) 
FROM @TempExchangeRates a 
     INNER JOIN @TempExchangeRates b 
      ON a.ToCurrency = b.FromCurrency 
      AND a.FromCurrency != b.ToCurrency 
WHERE NOT EXISTS 
     ( SELECT 1 
      FROM @TempExchangeRates c 
      WHERE a.FromCurrency = c.FromCurrency 
      AND  b.ToCurrency = c.ToCurrency 
     ) 

和插入的结果,直到所有的组合已被发现:

WHILE (1 = 1) 
    BEGIN 
     INSERT @TempExchangeRates (FromCurrency, ToCurrency, ExchangeRate) 
     SELECT DISTINCT a.FromCurrency, b.ToCurrency, CAST(a.ExchangeRate * b.ExchangeRate AS DECIMAL(10, 5)) 
     FROM @TempExchangeRates a 
       INNER JOIN @TempExchangeRates b 
        ON a.ToCurrency = b.FromCurrency 
        AND a.FromCurrency != b.ToCurrency 
     WHERE NOT EXISTS 
       ( SELECT 1 
        FROM @TempExchangeRates c 
        WHERE a.FromCurrency = c.FromCurrency 
        AND  b.ToCurrency = c.ToCurrency 
       ) 

     IF @@ROWCOUNT = 0 
      BEGIN 
       BREAK; 
      END 
    END 

在第一个循环,这将检索

CHF USD 1.04166 
EUR JPY 1.56000 
JPY EUR 0.64102 
USD CHF 0.96000 

然后在第二

JPY USD 0.80128 
USD JPY 1.24800 

然后,所有12元组将有被发现。