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
我有两个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