简体   繁体   English

如何在SQL中生成所有可能的汇率组合

[英]How to generate all the possible combinations of exchange rates in SQL

Given a table of tuples of currency and exchange rate, such as the following: 给出货币和汇率元组的表格,如下所示:

EUR CHF 1.20
USD EUR 0.80
CHF JPY 1.30

How can I simply generate all the exchange rate between currency (A,B) and also (B,A)? 如何简单地生成货币(A,B)和(B,A)之间的所有汇率?

I would like to have the following: 我想要以下内容:

EUR CHF
CHF EUR

EUR USD
USD EUR

USD CHF
CHF USD

with all the possible combinations, ie a rate can be derived from multiple rates by chaining them 具有所有可能的组合,即通过链接它们可以从多个速率导出速率

A to B * B to C * C to D = A to D

The only way I can find to do this is using a LOOP, All my queries below use this sample data: 我能找到的唯一方法就是使用LOOP,我下面的所有查询都使用这个示例数据:

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);

The first step is to get all the reciprocal exchange rates (ie B -> A from the table of A -> B) as these are the easiest to get: 第一步是获得所有互惠汇率(即A - > B表中的B - > A),因为这些是最容易获得的:

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
        )

At this point we have: 此时我们有:

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

So we are still missing 所以我们仍然缺席

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

You need to keep performing this join 您需要继续执行此连接

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
        )

And inserting the results until all combinations have been found: 并插入结果直到找到所有组合:

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

On the first loop this will retrieve 在第一个循环中,这将检索

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

Then on the second 然后在第二个

JPY USD 0.80128
USD JPY 1.24800

Then all 12 tuples will have been found. 然后将找到所有12个元组。

You can do this with a Recursive Common Table Expression 您可以使用递归公用表表达式执行此操作

Setup: 设定:

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);

The CTE, which assumes all currency codes are exactly three characters: 假设所有货币代码的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 http://sqlfiddle.com/#!3/0fdc5

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM