过程因数字或值错误而失败
Procedure fails with numeric or value error
我正在研究从 table 中获取行并稍微更改名称以使总共 50 行的过程...如您将在代码中看到的那样。
但是,我遇到了一个问题
数字或值错误,如您在我尝试使用
的代码中看到的
dbms_output.put_line('some message');
但是我的输出不起作用,所以发现问题变得很麻烦。
错误提示
"PL/SQL: numeric or value error"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
如果有人能给我指出正确的方向(或者甚至如何让 dbms 工作),我将不胜感激
(我已经打开 dbms 并连接到服务器并设置了 serverouput;)
代码:
create or replace procedure bbt_phone_users (n in number) authid current_user
as
cursor r10 is select firstname, lastname, password_ from bbt_users_temp;
r10type r10%rowtype;
fn bbt_users_temp.firstname%type;
ln bbt_users_temp.lastname%type;
pass bbt_users_temp.password_%type;
tel varchar2(15);
keymap_ln varchar(4);
phone_end number(4);
name_end number;
begin
phone_end := 1000;
dbms_output.put_line('hey');
for i in 1 .. n
loop
open r10;
fetch r10 into fn, ln, pass;
close r10;
for oneRow in r10
loop
name_end := name_end + 1;
dbms_output.put_line('works pre-1');
--1
-- each row gets the phone_end, which increments on each iteration
phone_end := phone_end + 1;
tel := '(317) 456-' || to_char(phone_end);
dbms_output.put_line('works after 1');
--2
-- takes the last name, and adds 000 and some number if its less than 10 OR
-- adds (concatinates) 00 and the numbers if its > 10
if name_end < 10 then
ln := ln || '000' || to_char(phone_end, '9');
else
ln := ln || '00' || to_char(phone_end, '99');
end if;
dbms_output.put_line('works after 2');
--3
-- calls the KEYMAP function and passes it the lastname
keymap_ln := KEYMAP(ln);
dbms_output.put_line('works after 3');
--4
-- inserts all our values
insert into phone_users values(tel, fn, ln, keymap_ln, pass);
--5
--rest are ignored since we don't do anything with them
end loop;
end loop;
end;
/
call bbt_phone_users(10);
select * from phone_users;
您已将 ln
声明为与 bbt_users_temp.lastname
相同的数据类型和大小。然后您尝试向其附加五个字符。因此,如果您第一次获取的任何值(这是不确定的,因为游标查询没有 order-by 子句)在该列的最大允许长度的五个字符以内,您将在第一次内循环时得到错误。
假设您的专栏是 varchar2(20)
。如果第一个获取的值是 16 个字符或更多 - 例如'Vandroogenbroeck' - 然后 ln
将从该值开始,长度为 16。然后您执行:
ln := ln || '00' || to_char(phone_end, '99');
将五个字符附加到现有值,使长度为 21。这对于变量来说太长了。
即使使用更短的值,例如 'Chamberlain',第一次循环时您添加了五个字符,这样总数为 16 并且没问题,但是第二次循环中您添加了另外 5 个字符到 that - 不是原来的 - 这再次使第二个值 21,而且太长了。即使使用更短的名称和更长的列,它也不会超过限制。
这不是重点,但您可能只希望它附加四个字符。它实际上总是附加 '00###'
。您尚未将 name_end
初始化为始终为 null,然后您进入 else
,它附加 '00'
,然后尝试使用掩码 99
格式化 phone_end
.因为此时 phone_end
是 1001,所以它不适合两位数,因此您将得到 ##
;但你也可以获得标志位置的奖励。
您可能正在尝试考虑不同的起始 phone_end
。您可以将 if/else/end 块替换为单个大格式模型,该模型在左侧用零填充,并抑制符号值的 space(您可能希望对 tel
值执行此操作也是):
ln := ln || to_char(phone_end, 'FM0000');
但这只是问题的一小部分;现在你每次循环只添加四个字符而不是五个,所以你可能只需要稍微长一点的时间来解决错误。
您可能希望每次都将这四个字符附加到相同的初始字符串,或者附加到当前光标行的值。如果源表和目标表中的列长度相同,那么您可能需要在添加数字之前截断初始值以确保它适合。
不清楚您最终想要得到什么,并且循环逻辑看起来很可疑(您真的要在 bbt_users_temp
中插入 10 倍的行数吗?您认为如何如果总共超过 9000 行,phone_end
和格式化值会发生什么情况?)。您可以重新设计逻辑,并且您可能根本不需要游标循环——甚至 PL/SQL。没有样本数据和预期结果,以及更清晰的描述,无法确定。
我正在研究从 table 中获取行并稍微更改名称以使总共 50 行的过程...如您将在代码中看到的那样。
但是,我遇到了一个问题
数字或值错误,如您在我尝试使用
的代码中看到的 dbms_output.put_line('some message');
但是我的输出不起作用,所以发现问题变得很麻烦。
错误提示
"PL/SQL: numeric or value error"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
如果有人能给我指出正确的方向(或者甚至如何让 dbms 工作),我将不胜感激
(我已经打开 dbms 并连接到服务器并设置了 serverouput;)
代码:
create or replace procedure bbt_phone_users (n in number) authid current_user
as
cursor r10 is select firstname, lastname, password_ from bbt_users_temp;
r10type r10%rowtype;
fn bbt_users_temp.firstname%type;
ln bbt_users_temp.lastname%type;
pass bbt_users_temp.password_%type;
tel varchar2(15);
keymap_ln varchar(4);
phone_end number(4);
name_end number;
begin
phone_end := 1000;
dbms_output.put_line('hey');
for i in 1 .. n
loop
open r10;
fetch r10 into fn, ln, pass;
close r10;
for oneRow in r10
loop
name_end := name_end + 1;
dbms_output.put_line('works pre-1');
--1
-- each row gets the phone_end, which increments on each iteration
phone_end := phone_end + 1;
tel := '(317) 456-' || to_char(phone_end);
dbms_output.put_line('works after 1');
--2
-- takes the last name, and adds 000 and some number if its less than 10 OR
-- adds (concatinates) 00 and the numbers if its > 10
if name_end < 10 then
ln := ln || '000' || to_char(phone_end, '9');
else
ln := ln || '00' || to_char(phone_end, '99');
end if;
dbms_output.put_line('works after 2');
--3
-- calls the KEYMAP function and passes it the lastname
keymap_ln := KEYMAP(ln);
dbms_output.put_line('works after 3');
--4
-- inserts all our values
insert into phone_users values(tel, fn, ln, keymap_ln, pass);
--5
--rest are ignored since we don't do anything with them
end loop;
end loop;
end;
/
call bbt_phone_users(10);
select * from phone_users;
您已将 ln
声明为与 bbt_users_temp.lastname
相同的数据类型和大小。然后您尝试向其附加五个字符。因此,如果您第一次获取的任何值(这是不确定的,因为游标查询没有 order-by 子句)在该列的最大允许长度的五个字符以内,您将在第一次内循环时得到错误。
假设您的专栏是 varchar2(20)
。如果第一个获取的值是 16 个字符或更多 - 例如'Vandroogenbroeck' - 然后 ln
将从该值开始,长度为 16。然后您执行:
ln := ln || '00' || to_char(phone_end, '99');
将五个字符附加到现有值,使长度为 21。这对于变量来说太长了。
即使使用更短的值,例如 'Chamberlain',第一次循环时您添加了五个字符,这样总数为 16 并且没问题,但是第二次循环中您添加了另外 5 个字符到 that - 不是原来的 - 这再次使第二个值 21,而且太长了。即使使用更短的名称和更长的列,它也不会超过限制。
这不是重点,但您可能只希望它附加四个字符。它实际上总是附加 '00###'
。您尚未将 name_end
初始化为始终为 null,然后您进入 else
,它附加 '00'
,然后尝试使用掩码 99
格式化 phone_end
.因为此时 phone_end
是 1001,所以它不适合两位数,因此您将得到 ##
;但你也可以获得标志位置的奖励。
您可能正在尝试考虑不同的起始 phone_end
。您可以将 if/else/end 块替换为单个大格式模型,该模型在左侧用零填充,并抑制符号值的 space(您可能希望对 tel
值执行此操作也是):
ln := ln || to_char(phone_end, 'FM0000');
但这只是问题的一小部分;现在你每次循环只添加四个字符而不是五个,所以你可能只需要稍微长一点的时间来解决错误。
您可能希望每次都将这四个字符附加到相同的初始字符串,或者附加到当前光标行的值。如果源表和目标表中的列长度相同,那么您可能需要在添加数字之前截断初始值以确保它适合。
不清楚您最终想要得到什么,并且循环逻辑看起来很可疑(您真的要在 bbt_users_temp
中插入 10 倍的行数吗?您认为如何如果总共超过 9000 行,phone_end
和格式化值会发生什么情况?)。您可以重新设计逻辑,并且您可能根本不需要游标循环——甚至 PL/SQL。没有样本数据和预期结果,以及更清晰的描述,无法确定。