在oracle中创建存储过程时,看似执行,但实际上什么也没做。存储过程永远不会被保存。为什么?
When creating a stored procedure in oracle, it appears to execute, but it does nothing. The stored procedure never gets saved. Why?
我正在尝试使用 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
并 return 给用户。它必须受到限制,以免造成过多的内存消耗。这些是相当大的结果集,它们看起来像这样:
+--------------+----+----+----+----+-------+
| CURRENT_DATE | LM | AO | RO | FL | TOTAL |
+--------------+----+----+----+----+-------+
| 1/2/2012 | 01 | 02 | 03 | 04 | 10 |
+--------------+----+----+----+----+-------+
| 1/4/2013 | 02 | 03 | 04 | 05 | 14 |
+--------------+----+----+----+----+-------+
我需要看风景吗?存储过程?我需要什么?
您已将程序声明为:
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
,这意味着你要么根本没有创建它(你输入的代码是 i但没有执行它),或者你在两个不同的模式中工作。您没有在 create
调用中显示架构前缀,因此出于隐私原因,您可能会被删除,或者您正在创建和调用单独的会话。如果您当前的用户不拥有该过程并且没有同义词,您需要在它前面加上所有者 - 从 table 所有者猜测:
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;
/
但你还需要select into something when you're working in PL/SQL, e.g. declare local variables like l_timerange
etc. if you're going to be doing something with them locally. But you seem to be expecting multiple values, so you'd need to bulk select into a collection。但尚不清楚这应该实现什么。如果你想将这些值传递回调用者,使用 ref cursor 到 return 结果集可能更简单;但是如果你真的需要一个 procedure/function ,或者只是一个普通的 SQL 查询,或者可能是一个视图,那就不是很清楚了...
作为进一步的问题,您将日期作为字符串进行比较,并且 grouping/ordering 也被那些比较:
to_char(TIME_RANGE, formatty) >= to_char(start, formatty)
比较仅适用于某些格式,并且当您在其中传递可变格式时会出现问题;即使它有效,也可能效率不高。排序也只适用于某些格式——如果排序有意义的话(同样,取决于你对结果做了什么!)。使用传入的格式将传递的 start/end 字符串转换为日期,然后进行比较:
TIME_RANGE >= to_date(p_start, formatty)
... 或者如果可能,将日期而不是字符串传递到过程中。
像这样捕获异常也很危险。您假设调用该过程的人将启用服务器输出并将对错误进行处理。除非你能明智地处理异常,否则你不应该捕获它,当然也不应该像这样压缩它。
如果我是你,我会这样编写上述过程:
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;
/
注:
- 将 out 参数添加到 return 光标
open p_ref_cursor for
行的附加项,它创建了指向光标的指针
- 更改谓词以将日期比较作为 DATE 而不是字符串
- 在结束
END
行后添加过程名称
- 参数名称更清晰。我建议也将过程的名称更改为更清晰的名称 - 这样,您的代码将变得更加自文档化并且将来更易于维护。
- 我将查询的基础移动到子查询并将外部查询更改为直接按 time_range 字段排序的方式 - 因为这仍然是 DATE 格式,它将结果排序为预期的。感谢 Alex Poole 指出排序问题。
至于你的问题 运行在 Toad 中解决这个问题,某些版本的 Toad 有一个错误(根据我的经验),其中 运行通过 Execute as statement / F9 按钮解决代码失败做任何事情。如果是这种情况,请尝试 运行将其作为脚本 (F5)。
要在 Toad(作为脚本)或 SQL*Plus 中测试上述过程,运行 以下内容:
variable rc refcursor;
begin
PottyUseRange('YYYY-MM-DD', '1/1/2008', '10/12/2015', :rc);
end;
/
print rc;
(这会创建一个 SQLPlus 变量 "rc",您将其作为绑定变量传递到过程中。然后您可以使用 SQLPlus 打印函数循环并显示结果。)
FWIW,这是我 运行 在 SQL*Plus:
中显示错误时看到的内容
SQL*Plus: Release 11.2.0.3.0 Production on Mon Oct 12 17:34:32 2015
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Enter password:
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options
SQL> create or replace procedure test
2 as
3 begin
4 null;
5 end test;
6 /
Procedure created.
SQL> show errors;
No errors.
SQL>
您应该在执行程序之前成功编译程序。
要查看编译错误,您可以使用 SHOW ERRORS
。从那里您可以得到 select 语句中的错误。
执行以下查询以了解编译时的错误
select * from SYS.USER_ERRORS where lower(NAME) = 'pottyuserange ' and type = 'PROCEDURE'
我正在尝试使用 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
并 return 给用户。它必须受到限制,以免造成过多的内存消耗。这些是相当大的结果集,它们看起来像这样:
+--------------+----+----+----+----+-------+
| CURRENT_DATE | LM | AO | RO | FL | TOTAL |
+--------------+----+----+----+----+-------+
| 1/2/2012 | 01 | 02 | 03 | 04 | 10 |
+--------------+----+----+----+----+-------+
| 1/4/2013 | 02 | 03 | 04 | 05 | 14 |
+--------------+----+----+----+----+-------+
我需要看风景吗?存储过程?我需要什么?
您已将程序声明为:
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
,这意味着你要么根本没有创建它(你输入的代码是 i但没有执行它),或者你在两个不同的模式中工作。您没有在 create
调用中显示架构前缀,因此出于隐私原因,您可能会被删除,或者您正在创建和调用单独的会话。如果您当前的用户不拥有该过程并且没有同义词,您需要在它前面加上所有者 - 从 table 所有者猜测:
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;
/
但你还需要select into something when you're working in PL/SQL, e.g. declare local variables like l_timerange
etc. if you're going to be doing something with them locally. But you seem to be expecting multiple values, so you'd need to bulk select into a collection。但尚不清楚这应该实现什么。如果你想将这些值传递回调用者,使用 ref cursor 到 return 结果集可能更简单;但是如果你真的需要一个 procedure/function ,或者只是一个普通的 SQL 查询,或者可能是一个视图,那就不是很清楚了...
作为进一步的问题,您将日期作为字符串进行比较,并且 grouping/ordering 也被那些比较:
to_char(TIME_RANGE, formatty) >= to_char(start, formatty)
比较仅适用于某些格式,并且当您在其中传递可变格式时会出现问题;即使它有效,也可能效率不高。排序也只适用于某些格式——如果排序有意义的话(同样,取决于你对结果做了什么!)。使用传入的格式将传递的 start/end 字符串转换为日期,然后进行比较:
TIME_RANGE >= to_date(p_start, formatty)
... 或者如果可能,将日期而不是字符串传递到过程中。
像这样捕获异常也很危险。您假设调用该过程的人将启用服务器输出并将对错误进行处理。除非你能明智地处理异常,否则你不应该捕获它,当然也不应该像这样压缩它。
如果我是你,我会这样编写上述过程:
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;
/
注:
- 将 out 参数添加到 return 光标
open p_ref_cursor for
行的附加项,它创建了指向光标的指针- 更改谓词以将日期比较作为 DATE 而不是字符串
- 在结束
END
行后添加过程名称 - 参数名称更清晰。我建议也将过程的名称更改为更清晰的名称 - 这样,您的代码将变得更加自文档化并且将来更易于维护。
- 我将查询的基础移动到子查询并将外部查询更改为直接按 time_range 字段排序的方式 - 因为这仍然是 DATE 格式,它将结果排序为预期的。感谢 Alex Poole 指出排序问题。
至于你的问题 运行在 Toad 中解决这个问题,某些版本的 Toad 有一个错误(根据我的经验),其中 运行通过 Execute as statement / F9 按钮解决代码失败做任何事情。如果是这种情况,请尝试 运行将其作为脚本 (F5)。
要在 Toad(作为脚本)或 SQL*Plus 中测试上述过程,运行 以下内容:
variable rc refcursor;
begin
PottyUseRange('YYYY-MM-DD', '1/1/2008', '10/12/2015', :rc);
end;
/
print rc;
(这会创建一个 SQLPlus 变量 "rc",您将其作为绑定变量传递到过程中。然后您可以使用 SQLPlus 打印函数循环并显示结果。)
FWIW,这是我 运行 在 SQL*Plus:
中显示错误时看到的内容SQL*Plus: Release 11.2.0.3.0 Production on Mon Oct 12 17:34:32 2015
Copyright (c) 1982, 2011, Oracle. All rights reserved.
Enter password:
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options
SQL> create or replace procedure test
2 as
3 begin
4 null;
5 end test;
6 /
Procedure created.
SQL> show errors;
No errors.
SQL>
您应该在执行程序之前成功编译程序。
要查看编译错误,您可以使用 SHOW ERRORS
。从那里您可以得到 select 语句中的错误。
执行以下查询以了解编译时的错误
select * from SYS.USER_ERRORS where lower(NAME) = 'pottyuserange ' and type = 'PROCEDURE'