create or replace procedure pr
is
v_date date;
begin
select sysdate into v_date from dual;
DBMS_output.put_line(v_date);
end pr;
3 回答
SQL 语句中不允许使用过程,因为混合使用声明式和命令式编程风格会造成混淆。
SQL 语句是一个条件列表——由 Oracle 决定如何生成与这些条件匹配的结果集。PL/SQL 存储过程是一组以非常可预测的方式改变事物的指令。
在下面的例子中,应该pr
执行多少次?它是在之前还是之后执行id = 1
?如果 SQL 语句具有预定义的顺序,那么优化器将无法推送谓词、合并子查询等,并且性能将无法接受。
select *
from table1
where id = 1
and pr;
即使在select
列表中使用了一个过程,它也可能没有意义。例如,总是忽略select
an 中的列表。exists
select * from dual where exists (select pr from dual);
但实际上SQL语句有时需要与外界交互,需要一些过程逻辑。函数是允许的,因为它们通常只是计算一些东西并返回一个值。函数通常不依赖于程序状态并且有很多副作用。您的函数可以使用会话变量、更新表(如果设置为PRAGMA AUTONOMOUS TRANSACTION
)、设置上下文等。Oracle 无法阻止您执行这些操作,但在 SQL 语句中禁止过程至少会阻止此类代码。
过程不能使用 select 语句执行,如果您想使用 select 语句执行,可以使用函数。
如果您想使用 select 语句执行过程,那么一种方法是使用函数包装您的过程并使用 select 语句调用函数。
CREATE OR REPLACE PROCEDURE pr (o_param OUT DATE)
IS
v_date DATE;
BEGIN
SELECT SYSDATE
INTO v_date
FROM DUAL;
o_param := v_date;
END pr;
现在用一个函数包装这个过程
CREATE OR REPLACE FUNCTION my_funct
RETURN DATE
AS
o_param DATE;
BEGIN
pr (o_param);
RETURN o_param;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (
DBMS_UTILITY.format_error_backtrace || ' ' || SQLERRM
);
-- raise exception
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
DBMS_UTILITY.format_error_backtrace || ' ' || SQLERRM
);
-- raise exception
END my_funct;
/
并使用 select 语句调用函数
SELECT my_funct FROM DUAL
CREATE OR REPLACE PROCEDURE count_salas IS V_count NUMBER(3);
BEGIN
SELECT COUNT(SALES.SALEQTY) as sales INTO V_count
FROM SALES INNER JOIN EMPLOYEE ON EMPLOYEE.EMPID = SALES.EMPID WHERE EMPLOYEE.EMPID = '101';
DBMS_OUTPUT.PUT_LINE(V_count); END V_count;