调用存储过程内部的“函数”

时间:2010-04-08 17:17:06

标签: sql oracle

我有一个包含大量INSERT的大型存储过程。有许多INSERTS几乎相同 - 它们因某些参数而不同(所有INSERT到同一个表)

有没有办法创建一个函数/方法,我将传递上述参数,函数/方法将生成具体的INSERT?

由于

3 个答案:

答案 0 :(得分:5)

不确定。创建私有函数很容易。

create or replace procedure p1 as

    n pls_integer;

    function private_f return number is
    begin
        return n;
    end private_f;
begin
    n := private_f;
end p1;

需要注意的是私有过程和函数定义必须是declare块中的最后一个声明。也就是说,我们不能在私有函数和外部过程的begin子句之间声明任何变量。

我没有向您展示如何实现在表中插入行的私有函数。那是因为这是一种糟糕的做事方式。在基于集合的方式中使用SQL更有效。

你没有说出参数的来源,所以我会做点什么。

工作示例

此过程模拟ETL过程。它从登台表中获取一些数据并将其挂载到PL / SQL集合中。然后它以某种方式操作加载的数据,然后使用批量插入语句将数据放入目标表中。

SQL> create or replace procedure pop_emps
  2      ( p_mgr in emp.mgr%type)
  3  as
  4      type emp_nt is table of emp%rowtype;
  5      new_emps emp_nt;
  6  begin
  7      --  populate array from staging table
  8      select emp_seq.nextval
  9             , t.ename
 10             , t.job
 11             , p_mgr
 12             , trunc(sysdate)
 13             , t.sal
 14             , null
 15             , t.deptno
 16      bulk collect into new_emps
 17      from emp_import t;
 18      -- fix some special values
 19      for i in new_emps.first..new_emps.last
 20      loop
 21          if new_emps(i).deptno = 50
 22          then
 23              new_emps(i).job := 'PLUMBER';
 24              new_emps(i).mgr := 8061;
 25          end if;
 26      end loop;
 27      --  insert new rows into EMP table
 28      forall j in new_emps.first..new_emps.last
 29          insert into emp
 30              values new_emps(j);
 31  end  pop_emps;
 32  /

Procedure created.

SQL>

请注意,FORALL是一个设置操作而不是循环

无论如何,要显示它的工作原理,我将加载这三行...

SQL> select * from emp_import
  2  /

ENAME                       SAL     DEPTNO JOB
-------------------- ---------- ---------- --------------------
KESTELYN                   3500         30 MARKETING
LIRA                       3750         30 MARKETING
TRICHLER                   3500         50 MARKETING

SQL> exec pop_emps(7839)

PL/SQL procedure successfully completed.

SQL> select * from emp where hiredate = trunc(sysdate)
  2  /

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      8083 KESTELYN   MARKETING       7839 08-APR-10       3500                    30
      8084 LIRA       MARKETING       7839 08-APR-10       3750                    30
      8085 TRICHLER   PLUMBER         8061 08-APR-10       3500                    50

SQL>

编辑2

如果您真的想要执行私有函数,那么您可以将%ROWTYPE作为参数传递....

create or replace procedure pop_emps is
    new_row emp%rowtype;
    procedure pop_emp_row
        ( p_row in emp%rowtype)
    is 
    begin
        insert into emp
            values p_row;
    end pop_emp_row;
begin

    -- assign some values to new_row
    new_row.empno := emp_seq.nextval;
    new_row.ename := 'WHOEVER';
    new_row.hiredate := trunc(sysdate);
    -- etc, etc

    pop_emp_row(new_row);
end  pop_emps;
/

答案 1 :(得分:1)

你可以使用这样的东西

CREATE FUNCTION WEIGHTED_AVERAGE3 (n1 INT,n2 INT,n3 INT,n4 INT,v1 VARCHAR(50))
  RETURNS INT
  DETERMINISTIC
   BEGIN
    DECLARE i1,i2,i3,i4,avg INT;
    INSERT INTO sfdata VALUES(n1,n2,n3,n4,v1);
    RETURN 1;
   END|
Query OK, 0 rows affected (0.08 sec)
mysql> SELECT WEIGHTED_AVERAGE3(50,60,60,50,'Thoko')\G
*************************** 1. row ***************************
WEIGHTED_AVERAGE3(50,60,60,50,'Thoko'): 1
1 row in set (0.00 sec)
mysql> SELECT * FROM sfdata\G

但它最好用作存储过程,如此

DROP PROCEDURE IF EXISTS `sp_students_INSERT_byPK` 
GO

CREATE PROCEDURE sp_students_INSERT_byPK
     (
        IN  p_student_id                    INT(11)       , 
        IN  p_password                      VARCHAR(15)   , 
        IN  p_active_flg                    TINYINT(4)    , 
        IN  p_lastname                      VARCHAR(30)   , 
        IN  p_firstname                     VARCHAR(20)   , 
        IN  p_gender_code                   VARCHAR(1)    ,
        IN  p_is_on_staff                   TINYINT(4)    , 
        IN  p_birth_dttm                    DATETIME        
     )
BEGIN 

    INSERT INTO students
         (
           student_id                    , 
           password                      , 
           active_flg                    , 
           lastname                      , 
           firstname                     , 
           gender_code                   ,
           is_on_staff                   , 
           birth_dttm                    
         )
    VALUES 
         ( 
           p_student_id                    , 
           p_password                      , 
           p_active_flg                    , 
           p_lastname                      , 
           p_firstname                     , 
           p_gender_code                   , 
           p_is_on_staff                   ,
           p_birth_dttm                    
         ) ; 
END 

GO

找到here

答案 2 :(得分:0)

包内:

 PROCEDURE do_insert(parameter_1_i IN  table_name.column_name1%TYPE
                    ,parameter_2_i IN  table_name.column_name2%TYPE
                    ,parameter_3_i IN  table_name.column_name3%TYPE
                    ... all of the table column names here
                    )  
 IS
   /*  
   || Add proper exception handling to this procedure.
   */ 
   BEGIN   
     INSERT  
       INTO table_name  
          ( column_name1  
          , column_name2  
          , column_name3
          )  
    VALUES( parameter_1_i  
          , parameter_2_i  
          , parameter_3_i  
          ... all of the parameters, some will have the value of NULL  
          )  
   END do_insert;

这符合您问题中列出的要求。确保你做得恰当。 您可以更改参数列表以基于表接收记录,并在插入中插入记录而不是所有单个列。个人选择。