【问题标题】:PLSQL Procedural LogicPLSQL 过程逻辑
【发布时间】:2018-04-23 20:09:23
【问题描述】:

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

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

这是我目前所写的:

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; 

【问题讨论】:

  • 不客气。到目前为止,您尝试了什么。
  • 创建或替换函数 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;开始 P_NUM := P_INPUT;循环退出当 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);结束循环;返回 P_OUT_NUM;结束;
  • 请在您的问题中添加任何代码,而不是作为 cmets,并描述什么不起作用。另外,如果您可以将其小写以提高可读性,那就太好了。
  • 显然是一个家庭作业问题。但这是一个有趣的问题,需要对 Oracle SQL 函数有一些非显而易见的知识,所以值得回答。

标签: sql oracle plsql


【解决方案1】:

问题是将 1234 转换为 4321。字符串-y 解决方案(诚然使用未记录的内置)本身很简单:to_number(reverse(to_char(1234)))。坚持数字数据类型更麻烦。我的解决方案非常程序化:无疑存在更优雅的解决方案。

无论如何,要将 1234 变成 4321,我们需要生成 1 + 20 + 300 + 4000。我的解决方案依次隔离每个值并乘以适当的 10 次方。为了隔离我们使用带有负值的trunc() 的值。这会将小数点左侧的数字向下舍入。因此,trunc(1234,-3) 产生1000。要将其转换为所需的值,我们乘以 10 的负三次方。因此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;
    ....

【讨论】:

  • 是否还有一种方法可以将操作员的问题从投票的深渊中挽救出来?
  • 老实说,我认为反对者对他们所认为的懒惰的“做我的功课”问题的反应并不多。我已经解决了@williamrobertson 的评论,但这就是我所接受的所有修饰。就是这样。
【解决方案2】:

我喜欢按照 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() 函数,我觉得它有点“字符串”,即使它对数字进行操作。

【讨论】:

    猜你喜欢
    • 2011-11-04
    • 1970-01-01
    • 2011-05-28
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多