oracle货币换算用例

Using Cases for currency conversion in oracle

我有两个table

Payments_history

CREATE TABLE payments_history(payment_date , account_id , currency, amount) AS
SELECT  TO_DATE ('05/01/2022','DD/MM/YYYY'), 2291969088, 'GBP', 10.00  FROM DUAL UNION ALL
SELECT TO_DATE ('05/01/2022','DD/MM/YYYY'), 7851880663, 'USD', 20  FROM DUAL UNION ALL
SELECT  TO_DATE ('06/01/2022','DD/MM/YYYY'), 5326844767, 'USD', 3.000  FROM DUAL UNION ALL
SELECT  TO_DATE ('05/01/2022','DD/MM/YYYY'), 3668657617, 'EUR', 40  FROM DUAL UNION ALL
SELECT  TO_DATE ('06/01/2022','DD/MM/YYYY'), 9040142052, 'GBP', 30.000  FROM DUAL 

Historics_rates

Create TABLE Historics_rates(t_date,from_ccy,to_ccy,rate) AS
SELECT  TO_DATE ('06/01/2022','DD/MM/YYYY'),'GBP','EUR',1.1832 FROM DUAL UNION ALL
SELECT  TO_DATE ('06/01/2022','DD/MM/YYYY'),'AUD','GBP',0.5263 FROM DUAL UNION ALL
SELECT  TO_DATE ('06/01/2022','DD/MM/YYYY'),'EUR','GBP',0.8452 FROM DUAL UNION ALL
SELECT  TO_DATE ('05/01/2022','DD/MM/YYYY'),'USD','GBP',0.7388 FROM DUAL UNION ALL
SELECT  TO_DATE ('05/01/2022','DD/MM/YYYY'),'EUR','USD',1.1441 FROM DUAL 

我要查找的是 'daily amount GBP Equivalent per day for the last three months'。例如,在日期“05/01/2022”检查 Payments_history table 中的给定金额,如果货币为英镑,则将其添加到总额中,然后继续下一次付款,如果货币为美元,则下一步检查其等值的 GBP 汇率并将其转换为 GBP 并打印结果。如果金额是 from_ccy 不是 GBP 的某种货币,则跳过该交易

Date           Amount in GBP
2022-01-05        24.78 

这是我目前所做的

DECLARE

total NUMBER;

BEGIN
select PH.PAYMENT_DATE, 
CASE 
            WHEN PH.CURRENCY = 'GBP' THEN total = total + PH.AMOUNT
            WHEN PH.CURRENCY = 'USD' AND HR.from_ccy = 'USD' AND HR.to_ccy = 'GBP' THEN total = total + (PH.AMOUNT*HR."rate")
            WHEN PH.CURRENCY = 'AUD' AND HR.from_ccy = 'AUD' AND HR.to_ccy = 'GBP' THEN total = total + (PH.AMOUNT*HR."rate")
            WHEN PH.CURRENCY = 'EUR' AND HR.from_ccy = 'EUR' AND HR.to_ccy = 'GBP' THEN total = total + (PH.AMOUNT*HR."rate")
            ELSE 'CURRENCY NOT FOUND'
            END AS total
FROM "historic_rates" AS HR RIGHT JOIN PAYMENTS_HISTORY AS PH on HR."date" = PH.payment_date AND PH.Currency = HR."from_ccy"
WHERE Extract(Month from PH.payment_date) = Extract(month from add_months( sysdate, -3 )) GROUP BY PH.PAYMENT_DATE;

但它给我错误

[Err] ORA-06550: line 8, column 40:
PL/SQL: ORA-00905: missing keyword
ORA-06550: line 6, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 15, column 117:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:

   ( begin case declare end exception exit for goto if loop mod
   null pragma raise return select update while with
   <an identifier> <a double-quot

您的错误包括:

  • CASE 表达式的 THEN 子句中使用 = 是无效语法。
  • 您不能在定义列的 sub-query 中引用列别名(在 ORDER BY 子句中除外),因此您不能在 CASE 中使用 total表达式。
  • CASE 表达式需要在其所有输出中具有相同的数据类型,因此您不能混合使用数字和字符串。
  • GROUP BY PH.PAYMENT_DATE 但你没有围绕 CASE 表达式的任何聚合函数。
  • 如果你做总计,那么 'CURRENCY NOT FOUND' 不是你可以总计的东西。
  • 在 Oracle 中,table 别名前的 AS 是无效语法。
  • 您混合使用了带引号的标识符 HR."from_ccy" 和不带引号的标识符 HR.from_ccy。虽然可以在 table 中同时使用两者,但其中一个几乎肯定是错误的(并且使用带引号的标识符是不好的做法)并且您的 DDL 语句不使用引号。
  • 除非您真的打算从任何一年的 12 月开始获取行,否则不要只比较月份。比较从 3 个月前的月初到 two-months 前的月初之前的范围。
  • 您的 PL/SQL 块没有 END 语句。
  • 您正在 PL/SQL 中使用 SELECT 语句,但未使用 SELECT ... INTO
  • 您可能不想使用 PL/SQL。
  • None 您的样本数据来自 3 个月前(2021 年 12 月)。

像这样:

select PH.PAYMENT_DATE, 
       SUM(
         CASE 
         WHEN PH.CURRENCY = 'GBP'
         THEN PH.AMOUNT
         WHEN PH.CURRENCY IN ('USD', 'AUD', 'EUR')
         AND  HR.from_ccy = PH.CURRENCY
         AND  HR.to_ccy = 'GBP'
         THEN PH.AMOUNT*HR.rate
         END
       ) As total
FROM   historics_rates HR
       RIGHT JOIN PAYMENTS_HISTORY PH
       on     HR.t_date = PH.payment_date
          AND PH.Currency = HR.from_ccy
WHERE  PH.payment_date >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -3)
AND    PH.payment_date <  ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -2)
GROUP BY PH.PAYMENT_DATE;

其中,对于示例数据:

CREATE TABLE payments_history(payment_date , account_id , currency, amount) AS
SELECT TO_DATE ('05/12/2021','DD/MM/YYYY'), 2291969088, 'GBP', 10.00  FROM DUAL UNION ALL
SELECT TO_DATE ('05/12/2021','DD/MM/YYYY'), 7851880663, 'USD', 20  FROM DUAL UNION ALL
SELECT TO_DATE ('06/12/2021','DD/MM/YYYY'), 5326844767, 'USD', 3.000  FROM DUAL UNION ALL
SELECT TO_DATE ('05/12/2021','DD/MM/YYYY'), 3668657617, 'EUR', 40  FROM DUAL UNION ALL
SELECT TO_DATE ('06/12/2021','DD/MM/YYYY'), 9040142052, 'GBP', 30.000  FROM DUAL;

Create TABLE Historics_rates(t_date,from_ccy,to_ccy,rate) AS
SELECT  TO_DATE ('06/12/2021','DD/MM/YYYY'),'GBP','EUR',1.1832 FROM DUAL UNION ALL
SELECT  TO_DATE ('06/12/2021','DD/MM/YYYY'),'AUD','GBP',0.5263 FROM DUAL UNION ALL
SELECT  TO_DATE ('06/12/2021','DD/MM/YYYY'),'EUR','GBP',0.8452 FROM DUAL UNION ALL
SELECT  TO_DATE ('05/12/2021','DD/MM/YYYY'),'USD','GBP',0.7388 FROM DUAL UNION ALL
SELECT  TO_DATE ('05/12/2021','DD/MM/YYYY'),'EUR','USD',1.1441 FROM DUAL;

输出:

PAYMENT_DATE TOTAL
06-DEC-21 30
05-DEC-21 24.776

db<>fiddle here