过程因数值或值错误而失败

时间:2018-04-20 23:49:56

标签: sql oracle dbms-output

我正在制作一个程序来从表格中取行并略微更改名称以使总共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;

1 个答案:

答案 0 :(得分:1)

您已将ln声明为与bbt_users_temp.lastname相同的数据类型和大小。然后你试图附加五个字符。因此,如果您的第一次获取获得的值(由于游标查询没有order-by子句而不确定)在该列的最大允许长度的五个字符内,您将在第一次内循环时获得错误。 / p>

说您的专栏是varchar2(20)。如果第一个获取的值是16个字符或更多 - 例如&#39; Vandroogenbroeck&#39; - 然后ln将从该值开始,长度为16.然后执行:

ln := ln || '00' || to_char(phone_end, '99');

将五个字符附加到现有值,使长度为21.这对于变量来说太长了。

即使使用较短的值,也可以说是张伯伦&#39;,第一次绕过循环,你会追加5个字符,这使得总数为16并且没有问题,但是第二次循环你又追加了5个字符字符到 - 不是原来的 - 再次使第二个值21,太长。即使名称较短且列较长,也不会使may循环超过限制。

这不是重点,但您可能只希望它附加四个字符。它实际上总是附加'00###'。您尚未初始化name_end,因为它始终为空,您进入else,后跟'00',然后尝试使用掩码{{1}格式化phone_end }}。由于此时99为1001,因此它不会适合两位数,因此您将获得phone_end;但你也可以获得一个奖励一个标志位置。

据推测,您正试图考虑不同的起始##。您可以使用单个大型模型替换if / else / end块,该模型左侧使用零填充,并抑制符号值的空间(您可能也希望对phone_end值执行此操作):< / p>

tel

但这只是问题的一小部分;现在你只是每次绕循环而不是五个附加四个字符,所以你可能需要稍微长一点才能找到错误。

您可能要么每次都要将四个字符附加到相同的初始字符串,要么添加到当前光标行的值。如果源表和目标表中的列长度相同,那么您可能需要在添加数字之前截断初始值以确保它适合。

不清楚你最终想要做什么,并且循环逻辑看起来很可疑(你真的想在ln := ln || to_char(phone_end, 'FM0000'); 插入10倍的行数吗?你做了什么?您认为bbt_users_temp和格式化的值是否会发生,如果总共超过9000行?)。您可能能够重写逻辑,并且您可能根本不需要游标循环 - 甚至PL / SQL。如果没有样本数据和预期结果,以及更清晰的描述,则无法确定。