我已经读过关于多货币的不同问答,但没有一个对我来说是清楚的,或者没有提供关于我的用例的足够的细节.

Scenario:

RADDO公司有3个分支机构,分别是英国、法国和美国.拉多有基础货币美元.预算是以美元编制的.RADDO在数据库中存储支持的货币兑换率.

英国的员工以英镑创建采购订单,法国的员工以欧元创建采购订单.

问题1:采购订单/订单项目数据库表-分行所在地货币和当前汇率或以基础货币美元换算的金额应该存储什么?请记住,汇率必须是创建PO时的汇率.

问题2:为了能够以美元/基础货币生成报告,应该换算什么以及何时换算?

问3:如果有人说两年后将基础货币从美元改为澳元,会对现有数据产生什么影响?

问题4:处理多种货币的最佳方式是什么,这样应用程序就能处理最小的兑换量?

推荐答案

记住,你得到的答案是主观的.有了这个免责声明,我就可以开始建立这样一个系统了.

TL;DR:使用币种汇率表存储适用于不同币种和日期的币种汇率.以当地货币和计算出的美元值存储金额.


A Currency Rates Table

创建以下表单的货币表(FX汇率):

FX_RATES 
-------- 
SOURCE_CURRENCY  -- e.g. USD, GBP, EUR 
TARGET_CURRENCY  -- as above 
EXCHANGE_RATE    -- a suitable decimal field representing the conversion 
VALID_FROM_DATE  -- date range when the above exchange rate is valid 
VALID_TO_DATE    -- as above 
  • 前4列的组合将代表唯一记录.
  • It is recommended that whenever a record for a pair of currencies (USD -> GBP) is entered, the equivalent reverse record is also inserted (GBP -> USD), either with the true exchange rate (conversions one way might use a different rate than the other way), or with the inverse of the original record.
  • 对于一对货币,连续的行必须显示日期的连续性(即,对于一对货币,在恰好一行中不应该有不在VALID_FROM_DATEVALID_TO_DATE之间的日期).
  • 为方便起见,还可以输入具有数据库支持的最小日期和最大日期的单行('USD', 'USD', 1, smallest_date, largest_date).这使得处理以基础货币本身进行分录的情况变得更容易.
  • 您需要确定此表的货币汇率来源,以及更新频率.例如,您的财务团队可能会发布一份weekly汇率表(即使货币市场的价值每天都在变化).

示例表如下所示.尽管一行的结束日期和下一行的开始日期似乎有重叠,但查找操作只判断一列(即>= VALID_FROM_DATE AND < VALID_TO_DATE)是否相等

SOURCE_CURRENCY TARGET_CURRENCY EXCHANGE_RATE          VALID_FROM_DATE VALID_TO_DATE 
--------------- --------------- ---------------------- --------------- -------------- 
GBP             USD             1.250000               06-Mar-2017     13-Mar-2017 
GBP             USD             1.260000               13-Mar-2017     20-Mar-2017 
GBP             USD             1.240000               20-Mar-2017     27-Mar-2017 
GBP             USD             1.250000               27-Mar-2017     03-Apr-2017 
USD             GBP             0.800000               06-Mar-2017     13-Mar-2017 
USD             GBP             0.793651               13-Mar-2017     20-Mar-2017 
USD             GBP             0.806452               20-Mar-2017     27-Mar-2017 
USD             GBP             0.800000               27-Mar-2017     03-Apr-2017 
USD             USD             1.000000               01-Jan-1900     31-Dec-9999 

Columns in PO Table

在采购订单表中,保留以下字段:

PURCHASE_ORDERS 
--------------- 
... other fields 
PO_TXN_DATE         -- Date for the PO that represents the financial transaction 
ORDER_VALUE_LOC     -- Decimal field with the order value in local currency 
ORDER_CURRENCY_LOC  -- The currency used for ORDER_VALUE_LOC (e.g. GBP/EUR) 
ORDER_VALUE_USD     -- The order value in USD (as this is the company's base currency) 
... other fields 

Populating the PO Columns

已经有一个流程填充PO表,必须扩展该流程才能填充以下字段:

  • PO_TXN_DATE是采购订单上的财务交易日期.根据您的业务规则,这可能是也可能不是创建/提出采购订单的日期.
  • ORDER_VALUE_LOC是以当地货币表示的交易价值.
  • ORDER_CURRENCY_LOC是当地货币的货币代码.
  • 这三个字段将用于查找外汇汇率表.
  • 通过在FX_RATES表中查找汇率来填充ORDER_VALUE_USD:

填充ORDER_VALUE_USD由以下伪代码演示

ORDER_VALUE_USD = PURCHASE_ORDERS.ORDER_VALUE_LOC * FX_RATES.EXCHANGE_RATE 
                  WHERE 
                        FX_RATES.SOURCE_CURRENCY = PURCHASE_ORDERS.ORDER_CURRENCY_LOC 
                    AND FX_RATES.TARGET_CURRENCY = 'USD' 
                    AND PURCHASE_ORDERS.PO_TXN_DATE >= FX_RATES.VALID_FROM_DATE 
                    AND PURCHASE_ORDERS.PO_TXN_DATE <  FX_RATES.VALID_TO_DATE 

Answers to OP's Questions

问题1:采购订单/订单项目数据库中应存储哪些内容 表-分行所在地币种和当前汇率或 以基础货币美元折算的金额是多少?请牢记在心 该汇率必须是创建PO时的汇率.

如前所述,在Purchase Orders表中存储本地货币值、交易日期、本地货币名称;还以基础货币(USD)计算和存储值.如果需要,汇率可以再查一次,不需要在这里重复存储.

USD值存储在这里是为了便于以单一货币进行聚合(例如,生成一个报告,显示要发送给总部的未完成PoS的总价值).如果对这种用例的需求很低,那么就不需要存储USD值,它可以根据需要的次数从FX汇率表中计算出来.然而,下面的问题意味着有合理的需要获得基础货币(美元)的价值.

问题2:要转换什么以及何时能够在美国生成报告 美元/基础货币?

通过同时以基础货币和美元存储价值,这样的报告将大大简化.这就是我们计算和存储美元值的一次性成本的原因,因此它可以被多次读取.

问题3:如果有人——比如说在2之后——对现有数据有什么影响

从技术上讲,如果预期会发生这样的变化,那么不要用USD来命名任何数据库 struct ,而是使用像BASE这样的通用名称.:-)

如果进行了此类变更,公司财务部门将指导您如何重述财务数据——例如,您是应该根据交易时的现行汇率重新计算基准值,还是只使用统一的换算系数?在任何情况下,一旦给出了这个决定,您只需要在FX_RATES表中输入适当的转换系数,然后运行一次性过程来重新填充PURCHASE_ORDERS.ORDER_VALUE_BASE列.除了汇率之外,PURCHASE_ORDERS表中已经存在并未更改此查找的所有其他信息.

问题4:处理多币种的最佳方式是什么? 处理最小数量的转换?

这将再次由您的业务需求驱动,而不是技术决策.如果需要经常报告本地货币和基础货币(美元),则以这两种货币存储相关交易值会有所帮助.通过计算一次并存储它,您可以从此后访问存储的数据中获益.

此外,由于您没有丢弃任何数据,因此如果需要,您可以随时重新计算财务数据.可能需要这样做的一些场景包括:

  • 公司决定使用提出采购订单时的现行汇率计算基础货币,但在采购订单关闭或开具发票时重新计算基础货币(美元).在这种情况下,您应该在关闭PO时使用不同的日期来查找FX_RATES表.
  • 如果拍击突然暴跌,从1英镑=1.25美元变成1英镑=1美元,你可能需要计算这样的变化对美元的影响.然后,您可以从FX_RATES表中获得存储值ORDER_VALUE_USD与使用今天的汇率重新计算的值之间的差额,以确定这种变化对美元的影响.

问5:交易时的汇率不能存储在 采购订单表?这样,系统就不需要查找 外汇汇率表中的汇率.(Asked via a follow-up comment)

汇率绝对可以存储在PO表中,而不是美元金额.在PO表中存储汇率本质上没有什么"错误",相反,存储美元金额也没有任何"正确"之处.

当然,这将导致一个问题-如果您一开始没有将汇率存储在某个查找表中,那么您从哪里获得汇率,以便将其填充到PO表中.请记住,在大型/全球公司中,外汇汇率很可能不会通过LOB应用程序本身填充,它将是一些外部来源,例如确定要在整个公司使用的外汇汇率的外汇汇率团队.在这种情况下,将外汇汇率存储在单独的表中会更方便.

我在下面列出了不同方法的一些好处.您需要根据您的需要 Select 您使用的一个(或多个).

  • Benefit of Storing USD in the PO Table:美元金额直接可用,无需进一步计算(即运行报告时无需计算ORDER_VALUE_LOC x EXCHANGE_RATE).
  • Benefit of a separate FX Rates table:外汇汇率集中存储在一个表中,便于更新&;审核(remember large corporations might have a separate team fixing the FX rates for company-wide use),以及验证(e.g. to check for continuity of FX rates - in the above example, it is trivially simple to check that there no gaps for FX rates by stringing together the valid from/to dates on successive rows).外汇汇率不会分散在多个表中.
  • Benefit of Storing FX Rate in the PO Table:不需要单独的FX_RATES张桌子.

当然,您可以冗余地存储附加信息(折算存储)以获得yield (例如,在PO表中存储本地货币金额、汇率和美元金额,并保留单独的汇率表.这使您可以轻松打印出显示当地货币金额和用于将其转换为美元金额的汇率的PO文档.与此同时,外汇汇率表仍然是一个权威的汇率来源).

记住,这个问题及其答案都是主观的,所以没有对与错.根据您的要求和贵公司的标准定制所有这些建议.

Database相关问答推荐

位置运算符($)工作不正确

为Postgres数据库字段创建复合索引

在MongoDB的树形 struct 中更新具有给定id的元素

UML 类图中关联的复杂规则

如何使用 Gramex FormHandler 动态(在运行时)创建或更改数据库模式

通过 mySQL 命令行直接上传图片

PostgreSQL - 按时间戳值分组?

repeating groups是什么意思?

如何识别 DB2 端口号

SQL 历史(history)表设计

如果我 for each 用户随机设置 SALT,我如何对他们进行身份验证?

如何关闭 Rails 中的updated_at列?

数据库中的整数与字符串

Django 数据库值的最佳推荐方式是什么?

SQL 中的 CAST 和 CONVERT 是否相同?

Spring data : CrudRepository 的保存方法和更新

DBMS中数据模型和数据库模式的区别?

我应该标准化我的数据库吗?

列的 SQL Server 2008 千位分隔符

如果值不为空,则用于更新数据库的 Sql 查询?