【问题标题】:Updating database tables when values are missing缺少值时更新数据库表
【发布时间】:2012-05-01 23:36:33
【问题描述】:

我有两张桌子:

比尔:

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

汇率:

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

这就是我想做的:

我想将我的 Bill 表更新为

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

在此更新中,包含该特定日期条目的所有行都将获得新的报告货币数据。由于 Bill 表可以有多个符合更新条件的行,我有以下问题:

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

【问题讨论】:

  • 哦。更正了我回答中的一个愚蠢错误。

标签: sql sybase sql-update


【解决方案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 子句

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 如果 ->最近的 BillDate 怎么办?我知道他没有要求,只是出于好奇。
    • OP 要求“最近的
    • 我知道。正如我出于好奇而说的,你将如何解决这个问题?
    猜你喜欢
    • 1970-01-01
    • 2016-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多