Коррелированный SQL-запрос соединения из нескольких таблиц - PullRequest
0 голосов
/ 30 марта 2010

У меня есть две таблицы, подобные приведенным ниже. Мне нужно выяснить, какой обменный курс действовал на дату покупки. Я пробовал некоторые коррелированные подзапросы, но у меня возникают трудности с получением коррелированной записи для использования в подзапросах.

Я ожидаю, что решение должно будет следовать этой основной схеме:

  1. ВЫБРАТЬ только exchangeRates для соответствующей страныCode
  2. С 1. ВЫБЕРИТЕ новейшую биржуRate меньше, чем dateOfPurchase
  3. Заполните таблицу запросов всеми полями из 2. и таблицы закупок.

Мои таблицы:

purchasesTable

> 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

Так, например, в результатах обменный курс, действовавший для евро 31 марта, составлял 1,75.

Я использую Access, но ответ на MySQL тоже подойдет.

UPDATE:

Изменение ответа Аллана:

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 

Мне пришлось сделать пару небольших изменений.

1 Ответ

3 голосов
/ 30 марта 2010

Если в вашей таблице 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]

Наконец, во внешнем соединении мы сообщаем запросу объединить все даты между этими двумяценности.Однако, поскольку один набор имеет нулевую конечную дату, мы добавляем условие или, чтобы игнорировать верхнюю границу в этом случае.


Я начал изучать SQL с Litwin, et.al.95 Руководство разработчика "и много читаю Usenet, так что мои источники немного устарели ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...