Why we can't execute stored procedure in selec

2019-02-16 01:55发布

问题:

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;

回答1:

Procedures are not allowed in SQL statements because mixing declarative and imperative programming styles is confusing.

A SQL statement is a list of conditions - it's up to Oracle to decide how to produce the result set that matches those conditions. A PL/SQL stored procedure is a set of instructions that change things in a very predictable way.

In the below example, how many times should pr be executed? Is it executed before or after id = 1? If SQL statements had a pre-defined order then the optimizer would not be able to push predicates, merge subqueries, etc., and performance would be unacceptable.

select *
from table1
where id = 1
    and pr;

Even if a procedure were used in the select list, it may not make sense. For example, the select list inside an exists is always ignored.

select * from dual where exists (select pr from dual);

But in reality SQL statements sometimes need to interact with the outside world, and some procedural logic is needed. Functions are allowed because they usually just calculate something and return a value. Functions normally do not depend on the program state and have a lot of side-effects. Your functions could use session variables, update tables (if it's set to PRAGMA AUTONOMOUS TRANSACTION), set a context, etc. Oracle can't stop you from doing those things, but disallowing procedures in SQL statements will at least discourage such code.



回答2:

Procedure cannot be executed using select statement, you can use function if you would want to execute using select statement.

If you would want to execute procedure using select statement then one approach is wrap your procedure with a function and call function using select statement.

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;

Now wrap the procedure with a function

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;
/

And call the function using select statement

SELECT my_funct  FROM DUAL


回答3:

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;