在oracle中创建存储过程时,它似乎执行,但它什么都不做。存储过程永远不会被保存。为什么?

时间:2015-10-12 15:03:13

标签: oracle plsql toad

我尝试使用TOAD在Oracle SQL中创建存储过程,但它没有做任何事情。在尝试创建它时没有错误,没有消息,没有任何错误。它似乎已经过去了,但它没有。

查询如下所示:

CREATE OR REPLACE PROCEDURE PottyUseRange (formatty varchar2, start varchar2, end varchar2)
AS
    BEGIN
        SELECT TO_CHAR(TIME_RANGE, formatty) as CURRENT_DATE,
            SUM(CASE WHEN PORTA_POTTY = 'LM' THEN 1 ELSE 0 END) as LM_SEARCH,
            SUM(CASE WHEN PORTA_POTTY = 'AO' THEN 1 ELSE 0 END) as AO_SEARCH,
            SUM(CASE WHEN PORTA_POTTY = 'RO' THEN 1 ELSE 0 END) as RO_SEARCH,
            SUM(CASE WHEN PORTA_POTTY = 'FL' THEN 1 ELSE 0 END) as FL_SEARCH,
            SUM(CASE WHEN PORTA_POTTY IN ('LM', 'AO', 'RO', 'FL') THEN 1 ELSE 0 END) as TOTAL           
        FROM CORE.DATE_TEST
            WHERE to_char(TIME_RANGE, formatty) >= to_char(start, formatty)
            AND to_char(TIME_RANGE, formatty) <= to_char(end, formatty)
        GROUP BY  TO_CHAR(TIME_RANGE, formatty)
        ORDER BY TO_CHAR(TIME_RANGE, formatty)  ASC;

        EXCEPTION WHEN OTHERS THEN
            raise_application_error(-20001,'Proc failed - '||SQLCODE||' -ERROR- '||SQLERRM);
    END;

当我试图打电话时(我知道它是一个空的查询,但它会让我知道它是否存在):

BEGIN
    POTTYUSERANGE();
END;

我收到此错误:PLS-00201: identifier 'POTTYUSERANGE' must be declared

当我使用CALL POTTYUSERANGE();调用它时,我收到此错误:ORA-06576: not a valid function or procedure name

如何为此查询正确创建存储过程?

更新

我需要将其插入BULK COLLECTION并将其返回给用户。它必须受到限制,因此不会导致过多的内存消耗。这些是相当大的结果集,它们看起来像这样:

+--------------+----+----+----+----+-------+
| CURRENT_DATE | LM | AO | RO | FL | TOTAL |
+--------------+----+----+----+----+-------+
|  1/2/2012    | 01 | 02 | 03 | 04 |  10   |
+--------------+----+----+----+----+-------+
|  1/4/2013    | 02 | 03 | 04 | 05 |  14   |
+--------------+----+----+----+----+-------+

我需要一个视图吗?存储过程?我需要什么?

4 个答案:

答案 0 :(得分:4)

您已将该程序声明为:

PottyUseRange (formatty varchar2, start varchar2, end varchar2)

但是你没有参数地调用它:

BEGIN
    POTTYUSERANGE();
END;

没有与您拨打的电话相匹配的程序。您需要传递适当数量的参数,这些参数可以是文字值,因为它们都是IN参数,例如:

BEGIN
    POTTYUSERANGE('X', 'Y', 'Z');
END;

当然,虽然价值更有意义。您也可以传递局部变量而不是常量文字。

但是你说你通过一个电话获得PLS-00201: identifier 'POTTYUSERANGE' must be declared,而ORA-06576: not a valid function or procedure name通过另一个电话获得,这意味着你要么根本没有实际创建它(你是&#39;键入代码但不执行它,或者您在两个单独的模式中工作。您尚未在create来电中显示架构前缀,因此出于隐私原因,您可能会将其删除,或者您正在创建和调用单独的会话。如果您当前的用户不拥有该程序并且没有同义词,则需要在其前面加上所有者 - 从表所有者那里猜测:

BEGIN
    CORE.POTTYUSERANGE('X', 'Y', 'Z');
END;

正如Lalit所说,无论如何你都有编译错误,所以调用会给PLS-00905: object SCHEMA.POTTYUSERANGE is invalid。您可以使用show errors或通过查询user_errors视图来查看错误(如果您正在另一个模式中创建对象,则可以all_errors,这在这里似乎就是这种情况),会告诉你:

PLS-00103: Encountered the symbol "START" when expecting one of the following:

         <an identifier> <a double-quoted delimited-identifier>
         current delete exists prior

开始和结束都是保留字。您可以使用更合适的名称(什么是开始?)或通用前缀,如p_

CREATE OR REPLACE PROCEDURE PottyUseRange (p_formatty varchar2, p_start varchar2, p_end varchar2)
AS
    BEGIN
        SELECT TO_CHAR(TIME_RANGE, formatty) as CURRENT_DATE,
            SUM(CASE WHEN PORTA_POTTY = 'LM' THEN 1 ELSE 0 END) as LM_SEARCH,
            SUM(CASE WHEN PORTA_POTTY = 'AO' THEN 1 ELSE 0 END) as AO_SEARCH,
            SUM(CASE WHEN PORTA_POTTY = 'RO' THEN 1 ELSE 0 END) as RO_SEARCH,
            SUM(CASE WHEN PORTA_POTTY = 'FL' THEN 1 ELSE 0 END) as FL_SEARCH,
            SUM(CASE WHEN PORTA_POTTY IN ('LM', 'AO', 'RO', 'FL') THEN 1 ELSE 0 END) as TOTAL           
        FROM CORE.DATE_TEST
            WHERE to_char(TIME_RANGE, p_formatty) >= to_char(p_start, formatty)
            AND to_char(TIME_RANGE, p_formatty) <= to_char(p_end, formatty)
        GROUP BY  TO_CHAR(TIME_RANGE, p_formatty)
        ORDER BY TO_CHAR(TIME_RANGE, p_formatty)  ASC;

        EXCEPTION WHEN OTHERS THEN
            raise_application_error(-20001,'Proc failed - '||SQLCODE||' -ERROR- '||SQLERRM);
    END;
/

但是当您在PL / SQL中工作时,您还需要select into。声明像l_timerange等局部变量,如果你要在本地做一些事情。但您似乎期待多个值,因此您需要bulk select into a collection。虽然不清楚这应该是什么。如果要将这些值传递回调用者,使用引用游标返回结果集可能更简单;但是,如果你真的需要一个过程/函数,或者只是一个普通的SQL查询,或者可能是一个视图,那么它并不是很清楚......

作为进一步的问题,您将日期比较为字符串,并按类别进行分组/排序:

to_char(TIME_RANGE, formatty) >= to_char(start, formatty)

比较只适用于某些格式,并且因为您在提出问题时传递了变量格式;即使它的工作可能效率不高。订购也只适用于某些格式 - 如果订购有意义(再次,取决于您对结果做了什么!)。使用传入的格式将传递的开始/结束字符串转换为日期,并比较它们:

TIME_RANGE >= to_date(p_start, formatty)

...或者如果可能的话,将日期传递给过程而不是字符串。

捕捉这样的例外情况也很危险。您假设调用该过程的任何人都将启用服务器输出并将对错误执行某些操作。除非你能够明智地处理一个例外,否则你不应该抓住它,当然也不应该这样做。

答案 1 :(得分:3)

如果我是你,这就是我对上述程序进行编码的方式:

declare namespace wijmo.Globalize {
    export function formatNumber(value: any, format: any, trim: any);
}

注意:

  1. 添加out参数以返回光标
  2. create or replace procedure pottyuserange (p_date_format in varchar2, p_start_date in varchar2, p_end_date in varchar2, p_ref_cursor out sys_refcursor) as begin open p_ref_cursor for select to_char(time_range, p_date_format) as current_date, lm_search, ao_search, ro_search, fl_search, total from (select trunc(time_range) time_range, sum(case when porta_potty = 'LM' then 1 else 0 end) as lm_search, sum(case when porta_potty = 'AO' then 1 else 0 end) as ao_search, sum(case when porta_potty = 'RO' then 1 else 0 end) as ro_search, sum(case when porta_potty = 'FL' then 1 else 0 end) as fl_search, sum(case when porta_potty in ('LM', 'AO', 'RO', 'FL') then 1 else 0 end) as total from core.date_test where trunc(time_range) >= to_date(p_start_date, p_date_format) and trunc(time_range) <= to_date(p_end_date, p_date_format) group by trunc(time_range)) order by time_range asc; end pottyuserange; / 行的附加内容,即创建指向游标的指针
  3. 更改谓词以将日期比较作为DATE而不是字符串
  4. 在结束open p_ref_cursor for
  5. 之后添加程序名称
  6. 参数名称的名称更清晰。我建议将程序的名称更改为更清晰的方式 - 这样,您的代码将变得更加自我记录并且将来更容易维护。
  7. 我将查询的基础移动到子查询并将外部查询更改为直接按time_range字段排序的方式 - 因为它仍然是DATE格式,它将按预期排序结果。感谢Alex Poole指出订购问题。
  8. 至于你在Toad中运行的问题,有些版本的Toad有一个错误(根据我的经验),通过Execute as statement / F9按钮运行代码无法执行任何操作。如果是这种情况,请尝试将其作为脚本运行(F5)。

    要在Toad(作为脚本)或SQL * Plus中测试上述过程,请运行以下命令:

    END

    (这会创建一个SQLPlus变量“rc”,您将其作为绑定变量传递给过程。然后,您可以使用SQLPlus打印功能循环并显示结果。)

    FWIW,这是我在SQL * Plus中运行show errors时看到的内容:

    variable rc refcursor;
    
    begin
      PottyUseRange('YYYY-MM-DD', '1/1/2008', '10/12/2015', :rc);
    end;
    /
    
    print rc;
    

答案 2 :(得分:0)

您应该在执行之前成功编译该过程。 要查看编​​译错误,您可以使用SHOW ERRORS。从那里你可以在你的select语句中得到错误。

答案 3 :(得分:0)

执行下面的查询以了解编译时的错误

scope