【问题标题】:Correlated SQL Join Query from multiple tables来自多个表的相关 SQL 连接查询
【发布时间】:2010-03-30 18:33:30
【问题描述】:

我有两张如下表。我需要找到在 dateOfPurchase 生效的 exchangeRate。我已经尝试了一些相关的子查询,但我很难让相关记录在子查询中使用。

我希望解决方案需要遵循以下基本大纲:

  1. 仅选择适用国家代码的 exchangeRates
  2. 从 1. 选择最新的 exchangeRate 小于 dateOfPurchase
  3. 使用 2. 和 purchaseTable 中的所有字段填写查询表。

我的表:

采购表

> dateOfPurchase    |   costOfPurchase  |   countryOfPurchase
> 29-March-2010 |   20.00       |   EUR
> 29-March-2010 |   3000        |   JPN
> 30-March-2010 |   50.00       |   EUR
> 30-March-2010 |   3000        |   JPN
> 30-March-2010 |   2000        |   JPN
> 31-March-2010 |   100.00      |   EUR
> 31-March-2010 |   125.00      |   EUR
> 31-March-2010 |   2000        |   JPN
> 31-March-2010 |   2400        |   JPN

costOfPurchase 以给定国家代码的当地货币表示


exchangeRateTable

> effectiveDate |   countryCode |   exchangeRate    
> 29-March-2010 |   JPN     |   90
> 29-March-2010 |   EUR     |   1.75
> 30-March-2010 |   JPN     |   92
> 31-March-2010 |   JPN     |   91

我要查找的查询结果:

> dateOfPurchase    |   costOfPurchase  |   countryOfPurchase   |   exchangeRate    
> 29-March-2010 |   20.00       |   EUR         |   1.75
> 29-March-2010 |   3000        |   JPN         |   90
> 30-March-2010 |   50.00       |   EUR         |   1.75
> 30-March-2010 |   3000        |   JPN         |   92
> 30-March-2010 |   2000        |   JPN         |   92
> 31-March-2010 |   100.00      |   EUR         |   1.75
> 31-March-2010 |   125.00      |   EUR         |   1.75
> 31-March-2010 |   2000        |   JPN         |   91
> 31-March-2010 |   2400        |   JPN         |   91

例如,在结果中,3 月 31 日对欧元有效的汇率为 1.75。

我正在使用 Access,但 MySQL 答案也可以。

更新:

修改艾伦的回答:

SELECT dateOfPurchase, costOfPurchase, countryOfPurchase, exchangeRate
FROM purchasesTable p 
     LEFT OUTER JOIN 
     (SELECT e1.exchangeRate, e1.countryCode, e1.effectiveDate, min(e2.effectiveDate) AS enddate
      FROM exchangeRateTable e1 
           LEFT OUTER JOIN
           exchangeRateTable e2
           ON e1.effectiveDate < e2.effectiveDate AND e1.countryCode = e2.countryCode
     GROUP BY e1.exchangeRate, e1.countryCode, e1.effectiveDate) e 
     ON p.dateOfPurchase >= e.effectiveDate AND (p.dateOfPurchase < e.enddate OR e.enddate is null) AND p.countryOfPurchase = e.countryCode 

我不得不做一些小改动。

【问题讨论】:

标签: sql mysql ms-access


【解决方案1】:

如果您的 exchangeRate 表没有任何差距,这很简单:

select dateOfPurchase, costOfPurchase, countryOfPurchase, exchangeRate
from purchasesTable p 
     inner join 
     exchangeRateTable e 
     on p.dateofpurchase = e.effectivedate 
        and p.countryofpurchase = e.countrycode 

如果确实存在差距(有效汇率设置为 1/1,直到 1/3 才改变,因此 1/1 汇率适用于 1/2),那么它会变得有点复杂,因为结束日期只是暗示。在这种情况下,以下应该有效:

select dateOfPurchase, costOfPurchase, countryOfPurchase, exchangeRate
from purchasesTable p 
     left outer join 
     (select e1.exchangeRate, e1.countrycode, 
             e1.effectivedate, min(e2.effectivedate) as enddate
      from exchangeRateTable e1 
           left outer join 
           exchangeRateTable e2
           on e1.effective_date < e2.effective_date 
              and e1.countrycode = e2.countrycode
           group by e1.exchangeRate, e1.countrycode, 
              e1.effectivedate) e 
     on p.dateofpurchase >= e.effectivedate
        and (p.dateofpurchase < e.enddate
             or e.enddate is null) 
        and p.countryofpurchase = e.countrycode 

如果您需要使用此解决方案,您可能希望将最里面的查询放在存储查询中,以简化此操作并使结束日期可用于其他进程。


我们正在做的是从汇率表 (e1) 中获取每条记录,并将其连接到同一张表 (e2) 中稍后出现的所有条目。我们取第二组值中的最小值 (min(e2.effectivedate))。

假设你只有三个值:

1/1/2000
1/3/2000
1/5/2000

连接将为您提供以下结果(每个值与所有更大的值相结合):

1/1/2000 < 1/3/2000
1/1/2000 < 1/5/2000
1/3/2000 < 1/5/2000
1/5/2000 < [null]

由于没有小于 1/5/2000 的值,并且我们指定了外连接,因此第二个表的该行将为空值。然后我们指定我们只想要第二个表中的最小值,因此结果集被简化为:

1/1/2000 < 1/3/2000
1/3/2000 < 1/5/2000
1/5/2000 < [null]

最后,在最外层连接中,我们告诉查询连接这两个值之间的所有日期。但是,由于一组的结束日期为空,因此我们添加一个 or 条件来忽略这种情况下的上限。


我从 Litwin 等人的“Access 95 Developer's Handbook”开始学习 SQL,并大量阅读 Usenet,所以我的资源有点过时了...

【讨论】:

  • 您先生,真是个天才。谢谢你。你有没有推荐一本书或网站来研究一些高级查询?
  • 另外,我不明白“从 exchangeRateTable e1 LEFT OUTER JOIN exchangeRateTable e2 ON e1.effectiveDate
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多