PLSQL错误:无效的数字

时间:2017-04-12 16:36:05

标签: sql oracle

我正在尝试执行此查询,这是我的过程的一部分,以及创建问题的那个:

select SUM(
                 CASE --DT007
              WHEN PRO.Sens_Mnt_Brut = 'D'
              THEN '-' || TO_CHAR(PRO.Mnt_Brut,'99999999999,99')
              WHEN PRO.Sens_Mnt_Brut = 'C'
              THEN '' || TO_CHAR(PRO.Mnt_Brut,'99999999999,99')
                END) OVER(PARTITION BY PRO.Num_Est_Remise) - SUM(TO_CHAR(PRO.Mnt_Comm_Tot_Ope,'99999999999,99')) OVER(PARTITION BY PRO.Num_Est_Remise))--DT015

From dlc_pr_operation pro; 

执行后我收到此错误:

ORA-01722: invalid number
01722. 00000 -  "invalid number"
*Cause:    
*Action:  

是因为从char转换为数字以及我要添加到查询中的逗号还是别的。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:3)

你在数字和字符串之间进行了大量的显式和隐式转换,并且不一致和假设使你绊倒。但无论如何它们都是不必要的 - 你根本不需要转换为字符串。您的查询可以重写为:

select SUM(
    CASE PRO.Sens_Mnt_Brut WHEN 'D' THEN -1 ELSE 1 END * PRO.Mnt_Brut
  ) OVER (PARTITION BY PRO.Num_Est_Remise)
    - SUM(PRO.Mnt_Comm_Tot_Ope) OVER(PARTITION BY PRO.Num_Est_Remise)
From dlc_pr_operation pro; 

根据Sens_Mnt_Brut标志决定,Mnt_Brut是应该按原样使用还是应该否定,并在适当的时候将它乘以1或-1。

您的方法至少有两个问题。您将数字转换为具有显式格式模型的字符串,然后将它们隐式转换回数字以对它们求和;这意味着(a)您依靠NLS设置进行隐式转换,并且(b)您正在形成的字符串无论如何都无法使用您的显式模型转换回来。

让我们从一些虚拟数据开始,这些数据会进入你的第一个分支:

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 1234.56, 1, 2 from dual
)
select to_number('-' || TO_CHAR(PRO.Mnt_Brut,'99999999999,99')) from dlc_pr_operation pro;

ORA-01722: invalid number

如果你看一下它形成的字符串,你会看到:

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 1234.56, 1, 2 from dual
)
select '-' || TO_CHAR(PRO.Mnt_Brut,'99999999999,99') from dlc_pr_operation pro;

'-'||TO_CHAR(PRO
----------------
-          12,35

由于所有空格,该字符串的转换失败。您可以使用略微修改的格式模型来避免这种情况:

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 1234.56, 1, 2 from dual
)
select to_number('-' || TO_CHAR(PRO.Mnt_Brut,'FM99999999999,99')) from dlc_pr_operation pro;

TO_NUMBER('-'||TO_CHAR(PRO.MNT_BRUT,'FM99999999999,99'))
--------------------------------------------------------
-12,35                                                  

但仅限于您的NLS设置,尤其是NLS_NUMERIC_CHARACTERS,是正确的。如果我在执行alter session set nls_numeric_characters = '.,'之后运行相同的查询,那么这也会得到ORA-01722,因为您使用了固定的逗号。您可以显式更改会话,也可以从使用固定,切换到通用D小数分隔符:

alter session set nls_numeric_characters = '.,';

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 1234.56, 1, 2 from dual
)
select to_number('-' || TO_CHAR(PRO.Mnt_Brut,'FM99999999999,99')) from dlc_pr_operation pro;

ORA-01722: invalid number

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 1234.56, 1, 2 from dual
)
select to_number('-' || TO_CHAR(PRO.Mnt_Brut,'FM99999999999D99')) from dlc_pr_operation pro;

TO_NUMBER('-'||TO_CHAR(PRO.MNT_BRUT,'FM99999999999D99'))
--------------------------------------------------------
                                                -1234.56

在整个查询过程中,这仍然会隐式转换回数字。

从这个答案的开头使用修改后的查询(如果你能记得那么远)而不是一些虚拟数据给出输出:

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 1234.56, 1, 2 from dual
  union all select 'X', 123.45, 2, 4 from dual
  union all select 'Y', 456.78, 3, 4 from dual
)
select SUM(
    CASE PRO.Sens_Mnt_Brut WHEN 'D' THEN -1 ELSE 1 END * PRO.Mnt_Brut
  ) OVER (PARTITION BY PRO.Num_Est_Remise)
    - SUM(PRO.Mnt_Comm_Tot_Ope) OVER(PARTITION BY PRO.Num_Est_Remise) as result
From dlc_pr_operation pro; 

    RESULT
----------
-1235,56  
575,23    
575,23    

由于没有转换,您的NLS设置现在不重要;除了最终结果由客户端自动使用会话的小数分隔符格式化,因此在此示例中它仍然显示逗号分隔符,数字字符设置为',.'。如果我将会话更改为'.,',我会看到:

    RESULT
----------
  -1235.56
    575.23
    575.23

您实际想要的结果是否不太明确。包含其他列可能很有用,但您还需要检查您是否真的需要分析函数,而不仅仅是聚合。

你在评论中说:

  

它是一个数字(16.0),但我想在最后两个数字之前加一个逗号

除非你将金融金额存储为整数 - 基本上是便士/美分而不是英镑/欧元/美元 - 但是希望以更友好的方式展示它们,这并不是真的有意义。在这种情况下,你应该将它们除以100,而不是将它们分成字符串:

with dlc_pr_operation (Sens_Mnt_Brut, Mnt_Brut, Mnt_Comm_Tot_Ope, Num_Est_Remise) as (
  select 'D', 123456, 100, 2 from dual
  union all select 'X', 12345, 200, 4 from dual
  union all select 'Y', 45678, 300, 4 from dual
)
select (SUM(
    CASE PRO.Sens_Mnt_Brut WHEN 'D' THEN -1 ELSE 1 END * PRO.Mnt_Brut
  ) OVER (PARTITION BY PRO.Num_Est_Remise) / 100)
    - (SUM(PRO.Mnt_Comm_Tot_Ope) OVER(PARTITION BY PRO.Num_Est_Remise) / 100) as result
From dlc_pr_operation pro; 

    RESULT
----------
  -1235.56
    575.23
    575.23

...假设(再次)两个被求和的值都是这样存储的;如果您愿意,也可以减去两个总和并将总数除以100。