缺少值时更新数据库表

时间:2009-03-06 09:54:50

标签: sql sybase sql-update

我有两张桌子:

比尔:

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

在此更新中,具有该特定日期条目的所有行将获得新的reportingcurrency数据。由于Bill表可以有多行符合更新条件,因此我遇到以下问题:

对于FxRate表中没有条目的行(对于该日期),ReportingCurrency变为NULL。我想回到nearest <= RateDate并获取汇率。是否可以在同一更新声明中使用修改或其他一些有效的方法? (我想避开光标)。

2 个答案:

答案 0 :(得分:1)

您应该可以使用子查询来实现此目的。希望我下面的例子可以不加修改地工作(并且没有错误!)唯一的注意事项是你需要用你的报告(基础)货币代替我假设的“美元”。

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子句

答案 1 :(得分:0)

当然这是可能的 - 作为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
  )