PLSQL程序逻辑

时间:2018-04-20 21:44:38

标签: sql oracle plsql

如何编写一个PL / SQL函数:

  1. 仅使用数值数据类型和函数 - 无VARCHAR2,CHAR,CLOB,XML等。 "换句话说,您的解决方案中不应使用REVERSE,SUBSTR等字符/字符串函数。
  2. 接受PLS_INTEGER参数
  3. 如果提供的值小于或等于零,则抛出应用程序错误-20001并提供良好的错误消息
  4. 以相反的顺序返回PLS_INTEGER值,该值包含输入参数的数字。如果输入值以一个或多个零结束,那么这些零将不会出现在返回的数值中,因为它们将是前导零。
  5. 这是我到目前为止所写的内容:

    create or replace function test_reverse
        (p_input in pls_integer) 
        return pls_integer 
    is
        p_num pls_integer := 0; 
        p_in_num pls_integer := 0; 
        p_out_num pls_integer := 0; 
    begin 
        p_num := p_input; 
        loop 
            exit when p_num p_in_num := mod(p_num,10); 
            p_out_num := (p_out_num * 10) + p_in_num;
            p_num := trunc(p_num / 10); 
        end loop; 
        return p_out_num; 
    end; 
    

2 个答案:

答案 0 :(得分:1)

问题是将1234变成4321.字符串-y解决方案(诚然使用未记录的内置函数)本身就是简单的:to_number(reverse(to_char(1234)))。坚持使用数值数据类型更加麻烦。我的解决方案非常具有程序性:毫无疑问,存在更优雅的解决方案。

无论如何,要将1234变为4321,我们需要生成1 + 20 + 300 + 4000.我的解决方案依次隔离每个值并乘以适当的10的幂。要隔离值,我们将trunc()与负值一起使用。这会将小数点左侧的数字向下舍入。因此,trunc(1234,-3)生成1000。要将其转换为所需的值,我们将乘以10乘以-3的幂。因此1000 * 10(-3) = 1

该函数遍历数字。将1000转换为1后,我们计算余数1234 - 1000 = 234。所以现在我们需要隔离200并将其转换为20;这是trunc(234, -2)power(200, -1)。因此,我们可以将偏移量递增到trunc()递减1,将指数递增到power()递增2。

这是一个工作函数(非常松散地基于你发布的函数):

create or replace function test_reverse
    (p_input in pls_integer) 
    return pls_integer 
is
    p_out_num pls_integer := 0;
    offset    pls_integer;
    tgt       pls_integer;
    rmdr      pls_integer;
    exp       pls_integer;
begin 
    rmdr := p_input;
    offset := length(p_input)-1;
    exp := -offset;
    loop 
        tgt := trunc(rmdr, -offset);
        p_out_num := p_out_num + (tgt * power(10, exp));
        exp := exp + 2;
        rmdr := rmdr - tgt;
        exit when offset = 0;
        offset := offset-1;
    end loop; 
    return p_out_num; 
end test_reverse; 
/

这是a LiveSQL demo (free Oracle Technet account required, alas)。这并不具备参数验证功能,但它足够简单:

create or replace function test_reverse
    (p_input in pls_integer) 
    return pls_integer 
is
    p_out_num pls_integer := 0;
    offset    pls_integer;
    tgt       pls_integer;
    rmdr      pls_integer;
    exp       pls_integer;
begin 
    if p_input <= 0 then
         raise_application_error(-20001
              'invalid input: ' || || ' must be greater than zero.'
         );
    end if; 
    rmdr := p_input;
    ....

答案 1 :(得分:1)

我喜欢使用modulo函数作为op建议:

CREATE OR REPLACE FUNCTION test_reverse (
    p_input IN PLS_INTEGER
) RETURN PLS_INTEGER 
IS
    remain   PLS_INTEGER := p_input;
    retval   PLS_INTEGER := 0;
BEGIN
    IF p_input < 1 THEN
        raise_application_error(-20001,'error: input must me greater than 0');
    END IF;
    LOOP
        retval := retval * 10 + MOD(remain,10);
        remain := trunc(remain / 10);
        EXIT WHEN remain = 0;
    END LOOP;
    RETURN retval;
END;
/

这也避免了使用length()函数,这种函数对我的品味感觉有些“细长”,即使它对数字有效。