PL / SQL:数字或值错误

0 oracle plsql ora-06502

我遇到错误,不知道为什么:

ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.STANDARD", line 394
ORA-06512: at "DOMINOS.DISTANCE", line 10
ORA-06512: at "DOMINOS.ZOEKWINKELVOORADRES", line 19
ORA-06512: at line 5
Run Code Online (Sandbox Code Playgroud)

光标应包含145行。当我执行该过程时,我在54行之后收到上面的错误消息。

create or replace procedure zoekWinkelVoorAdres
    (v_postcode in postcode.postcode%type,
      v_huisnr in WINKEL.HUISNR%type,
      v_id out WINKEL.ID%type,
      v_afstand out number)
is
    type lat_array is varray(100000) of POSTCODE.LAT%type;
    type lon_array is varray(100000) of POSTCODE.LON%type;
    type id_array is varray(100000) of winkel.id%type;
    a_lat lat_array;
    a_lon lon_array;
    a_id id_array;
    latwin postcode.lat%type;
    lonwin postcode.lon%type;
    latklant postcode.lat%type;
    lonklant postcode.lon%type;
    vafstand number(38);
    cursor winkelafstand is
        select w.ID, p.lat, p.lon 
        from winkel w 
        join postcode p 
        on w.POSTCODE_ID_FK = p.POSTCODE_ID;
begin
    select lat, lon into latklant,lonklant 
    from postcode 
    where postcode = v_postcode;
    open winkelafstand;
    fetch winkelafstand bulk collect into a_id, a_lat, a_lon;
    close winkelafstand;
    for i in a_lat.first..a_lat.last loop
        vafstand := distance(a_lat(i),a_lon(i),latklant,lonklant);
        dbms_output.put_line(vafstand || ' ' || a_id(i));
        insert into winkel_afstand
             (Winkel_ID, afstand) values(a_id(i),vafstand);
    end loop;
end;
/
Run Code Online (Sandbox Code Playgroud)

Ale*_*ole 5

通过一点搜索,如果为两组坐标赋予相同的位置,则似乎会出现此错误。

假设您的distance函数的定义类似于链接的示例:

CREATE OR REPLACE FUNCTION DISTANCE 
( 
Lat1 IN NUMBER, 
Lon1 IN NUMBER, 
Lat2 IN NUMBER, 
Lon2 IN NUMBER 
) RETURN NUMBER IS 
DegToRad NUMBER := 57.29577951; 
BEGIN
RETURN(6387.7 * ACOS((sin(NVL(Lat1,0) / DegToRad) * SIN(NVL(Lat2,0) / DegToRad)) + 
(COS(NVL(Lat1,0) / DegToRad) * COS(NVL(Lat2,0) / DegToRad) * 
COS(NVL(Lon2,0) / DegToRad - NVL(Lon1,0)/ DegToRad)))); 
END; 
/
Run Code Online (Sandbox Code Playgroud)

...然后,如果您两次传递同一对值,则由于四舍五入错误,计算结果将为无效值,例如

select distance(53.8662, 10.68117, 53.8662, 10.68117) from dual
Run Code Online (Sandbox Code Playgroud)

加入(1)调试对于组分(在功能,之间BEGINRETURN)所示:

dbms_output.put_line(lat1 ||','|| lon1);
dbms_output.put_line(sin(NVL(Lat1,0) / DegToRad));
dbms_output.put_line(SIN(NVL(Lat2,0) / DegToRad));
dbms_output.put_line(COS(NVL(Lat1,0) / DegToRad));
dbms_output.put_line(COS(NVL(Lat2,0) / DegToRad)); 
dbms_output.put_line(COS(NVL(Lon2,0) / DegToRad));
dbms_output.put_line(NVL(Lon1,0)/ DegToRad);

.8076421638813717679360124563997362950201
.8076421638813717679360124563997362950201
.5896729051949185735939828069514084977347
.5896729051949185735939828069514084977347
.9826737619730074300608748352929523713616
.1864215844752715888130518254292967904505
Run Code Online (Sandbox Code Playgroud)

当它们相乘并相加时,结果为:

1.00000000000000000000000000000000000001
Run Code Online (Sandbox Code Playgroud)

因此,至少在PL / SQL中RETURN(6387.7 * ACOS(1.00000000000000000000000000000000000001)),整个计算结果为,并ACOS(1.00000000000000000000000000000000000001)引发相同的错误:

declare
  result number;
begin
  result := acos(1.00000000000000000000000000000000000001);
end;
/

ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.STANDARD", line 394
ORA-06512: at line 4
Run Code Online (Sandbox Code Playgroud)

SQL函数得到另一个错误:

select acos(1.00000000000000000000000000000000000001) from dual;

SQL Error: ORA-01428: argument '1.00000000000000000000000000000000000001' is out of range
Run Code Online (Sandbox Code Playgroud)

...但是这是相同的问题,将大于1的值传递给ACOS没有意义。

作为一种解决方法,您可以ROUND()在调用之前将函数更改为值ACOS(),并使用足够高的参数以不显着影响其他计算,尽管对于任何舍入方法来说,它都不是完美的(但显然不是这样!):

  RETURN(6387.7 * ACOS(ROUND((
    (SIN(NVL(Lat1,0) / DegToRad) * SIN(NVL(Lat2,0) / DegToRad))
      + (COS(NVL(Lat1,0) / DegToRad)
        * COS(NVL(Lat2,0) / DegToRad)
        * COS(NVL(Lon2,0) / DegToRad - NVL(Lon1,0)/ DegToRad)
        )
    ), 9))
  ); 
Run Code Online (Sandbox Code Playgroud)

有了这个改变:

select distance(53.8662, 10.68117, 53.8662, 10.68117) from dual;

DISTANCE(53.8662,10.68117,53.8662,10.68
---------------------------------------
                                      0
Run Code Online (Sandbox Code Playgroud)

如果无法更改该函数,则必须比较这些值以确定调用它是否安全。