Обновление таблиц базы данных при отсутствии значений - PullRequest
0 голосов
/ 06 марта 2009

У меня есть две таблицы:

Счет:

create table Bill(
               BillDate datetime,
               Amount decimal(10,2) ,
               BillCurrency varchar(3) ,
               ReportingCurrency decimal(10,2))

FxRate:

create table FxRate( 
               RateDate datetime,
               SourceCurrency varchar(3),
               TargetCurrency varchar(3),
               ExchangeRate decimal(15,4))

Вот что я хочу сделать:

Я хочу обновить таблицу Билла как

update Bill 
set ReportingCurrency = FxRate.ExchangeRate * Bill.Amount
from FxRate
where FxRate.RateDate = Bill.BillDate

В этом обновлении все строки, в которых есть запись на эту конкретную дату, получат новые данные о валюте отчетности. Поскольку таблица Билл может иметь несколько строк, подходящих для обновления, у меня возникает следующая проблема:

Для строк, в которых не было записи в таблице FxRate (на эту дату), ReportingCurrency становится NULL. Я хочу вернуться к nearest <= RateDate и подобрать обменный курс. Возможно ли это с помощью модификаций в том же заявлении об обновлении или каким-либо другим эффективным методом? (Я хочу избежать курсора).

Ответы [ 2 ]

1 голос
/ 06 марта 2009

Вы должны быть в состоянии достичь этого с помощью подзапроса. Надеюсь, мой приведенный ниже пример будет работать без изменений (и не будет ошибок!). Единственное замечание: вам нужно заменить свою отчетную (базовую) валюту на предполагаемый «USD».

UPDATE Bill SET ReportingCurrency = (Bill.Amount * 
  (SELECT TOP 1 FxRate.ExchangeRate FROM FxRate
   WHERE FxRate.SourceCurrency = Bill.BillCurrency
   AND FxRate.TargetCurrency = 'USD'
   AND FxRate.RateDate <= Bill.BillDate
   ORDER BY FxRate.RateDate DESC))

Надеюсь, это поможет. РЕДАКТИРОВАТЬ - Добавлено предложение ORDER BY

0 голосов
/ 06 марта 2009

Конечно, это возможно - как SELECT это будет:

SELECT
  b.BillDate,
  r.RateDate,
  r.ExchangeRate
FROM
  Bill b
  LEFT JOIN FxRate r ON r.RateDate = (
    SELECT MAX(RateDate) FROM FxRate WHERE RateDate <= b.BillDate
  )

Следовательно, как ОБНОВЛЕНИЕ:

UPDATE
  Bill
SET
  ReportingCurrency = r.ExchangeRate * b.Amount
FROM
  Bill b
  LEFT JOIN FxRate r ON r.RateDate = (
    SELECT MAX(RateDate) FROM FxRate WHERE RateDate <= b.BillDate
  )

Решение делает следующие предположения:

  • никогда не бывает более одной FxRate записи за любой данный день
  • существует запись FxRate, которая предшествует всем Bill записям

Если эти предположения неприменимы, запрос должен быть удовлетворен.

Также обратите внимание, что это синтаксис SQL Server. Возможно, что Sybase немного отличается.


Поскольку комментатор проявил интерес к общему решению "ближайшей даты":

UPDATE
  Bill
SET
  ReportingCurrency = r.ExchangeRate * b.Amount
FROM
  Bill b
  LEFT JOIN FxRate r ON r.RateDate = (
    SELECT TOP 1 RateDate 
    FROM         FxRate
    ORDER BY     ABS(DATEDIFF(d, RateDate, b.BillDate)), RateDate
  )

Хотя это будет довольно медленно. Альтернатива:

UPDATE
  Bill
SET
  ReportingCurrency = CASE 
                      WHEN DATEDIFF(d, r1.RateDate, b.BillDate) <= DATEDIFF(d, b.BillDate, r2.RateDate)
                      THEN r1.ExchangeRate
                      ELSE COALESCE(r2.ExchangeRate, r1.ExchangeRate)
                      END * b.Amount
FROM
  Bill b
  LEFT JOIN FxRate r1 ON r1.RateDate = (
    SELECT MAX(RateDate) FROM FxRate WHERE RateDate <= b.BillDate
  )
  LEFT JOIN FxRate r2 ON r2.RateDate = (
    SELECT MIN(RateDate) FROM FxRate WHERE RateDate >= b.BillDate
  )
...