PLSQL过程编写体验

2011年5月19日  20:38:23

        2011年5月28日  修改

    这段时间写了一个PLSQL过程,今天让项目组经理给评审了,受益良多啊,赶紧将金玉良言记录下来:

       一段好代码必须让外人在最短的时间表看懂你所写的过程含义。

    1、注意编码中命名的规范性。

        各种包名,过程名,函数名,变量名都要让人一目了然,从命名中能直接明白含义。

    2、在代码中尽量不要使用 count,因为这个影响性能。也许刚开始没什么事,但是随着时间的推移,表的数据量会越来越大,很可能成为以后代码的瓶颈。

         若可以则用显式游标代替之。

        见如下语句:      

        SELECT COUNT(1) INTO v_status FROM itf_n9_sig@resource_link WHERE trunc(finishdate) = trunc(SYSDATE) AND       step_name='itf_n9_gis';

       改写为:   

CURSOR sig_cur IS
     SELECT 1
       FROM itf_n9_sig@resource_link
      WHERE trunc(finishdate) = trunc(SYSDATE)
        AND step_name = 'itf_n9_gis';
      然后在begin 和end之间通过打开游标,判断游标是否有值。

    3、在具体过程或函数的begin和end之间,尽量不要出现具体的sql语句。因为sql语句体现了业务逻辑,对于别人来说不容易看懂。也许可以通过游标来替代。

    4、尽量不要使用隐式游标。同4,隐式游标直接将sql语句放到begin。。end之间,这样不利于代码的可读性。若可以用显式游标替代之。

    5、对于不需要被外部调用的过程,函数,不要在包头中定义,只要在包头中定义了,就是公用了,可以被外部调用。所以尽量将包私有的过程和函数不在包头定义。这样在包体中每个过程的顺序就要按过程间的调用关系进行排列了(需要调用别的过程的过程要在被调用过程后面,因为plsql是从下往上找)。

    6、一个问题待确认。如果一个表的数据插入后未提交,是否能直接update?因为我自己在写的过程中就是因为发现了没有提交而导致没法更新,但是今天姜项目经理却给我临时验证在sql中是可以的。也许是自己理解错了,当时的那个问题并不是因为insert数据没有提交而导致代码错误。

       经过再次验证结论如下:

  原过程如下:

PROCEDURE syn_zytb_source(r_parameter gs_zytb_resource%ROWTYPE) IS
    v_sql  VARCHAR2(4000);
    
  BEGIN
    pkg_public.P_writeProgramLog(r_parameter.g3e_fno || '增量表开始更新');
    v_sql := pkg_public.f_replaceString('insert /*+append*/ into {1}  ({2}) select {3} from {4} d where not exists(select 1 from {1} where id=d.id)',
                           str_array(r_parameter.G3E_ZYTB_TABLE,
                                     r_parameter.G3E_ZYTB_COLUMNS,
                                     r_parameter.G3E_SOURSE_COLUMNS,
                                     r_parameter.G3E_SOURSE_TABLE));
 
    EXECUTE IMMEDIATE v_sql;--(1)     

COMMIT;   --该处的commit若省略,则无法执行后面的update语句。

v_sql := REPLACE('update {1} a set a.g3e_fid=g3e_fid_seq.nextval where a.processtype=''INSERT'' and a.g3e_fid is null /*and a.edite >=trunc(sysdate)*/',
                      '{'||1||'}',
                      r_parameter.G3E_ZYTB_TABLE);
    EXECUTE IMMEDIATE v_sql;
    v_sql := REPLACE('update {1} a set a.g3e_fid = (select g3e_fid from {1} where a.sourceid = sourceid and processtype = ''INSERT'') where a.processtype = ''UPDATE'' and a.g3e_fid is null /*and a.edite >= trunc(sysdate)*/',
                      '{'||1||'}',
                      r_parameter.G3E_ZYTB_TABLE);
    EXECUTE IMMEDIATE v_sql;
    v_sql := REPLACE('update {1} a set a.g3e_fid = (select g3e_fid from {1} where a.sourceid = sourceid and processtype = ''INSERT'') where a.processtype = ''DELETE'' and a.g3e_fid is null /*and a.edite >= trunc(sysdate)*/',
                      '{'||1||'}',
                      r_parameter.G3E_ZYTB_TABLE);
    EXECUTE IMMEDIATE v_sql;
    COMMIT;
    pkg_public.P_writeProgramLog(r_parameter.g3e_fno || '增量表更新成功');
    
    EXCEPTION
    WHEN OTHERS THEN
      ROLLBACK;
    pkg_public.P_writeProgramLog((sqlerrm) || substr(v_sql, 1, 2000) ||
                        r_parameter.g3e_fno || '增量表更新出错');
  END;

     如果将以上代码的(1)insert sql语句改成静态的,那么该过程中在对表itf_zytb_exch之后就不用先commit可以直接进行后面的update操作。

     insert 语句改成静态的如下所示:

v_sql := 'INSERT  /* +append*/
              INTO itf_zytb_exch
                  (id,sourceid,station_id,processtype,prj_no,edite,super_station_name,station_no,china_name_ab,district_name,
                   childregion_name,union_station_no,union_china_name,region2_name,building_kind_name,mnt_spec_name,location,
                   type_name,grade_name,isstation,linkman,phone,builddate,building_wiring,including_range,building_fghs,
                   buliding_xqsx,building_jrsx,busi_permit_range,open_time,china_name_full,building_up_point,building_up_rme,
                   building_up_method,building_pm,building_rme,open_no,submit_man,x,y,station_type_name)
           SELECT id,sourceid,station_id,processtype,prj_no,edite,super_station_name,station_no,china_name_ab,district_name,
                  childregion_name,union_station_no,union_china_name,region2_name,building_kind_name,mnt_spec_name,location,
                  type_name,grade_name,isstation,linkman,phone,builddate,building_wiring,including_range,building_fghs,
                  buliding_xqsx,building_jrsx,busi_permit_range,open_time,china_name_full,building_up_point,building_up_rme,
                  building_up_method,building_pm,building_rme,open_no,submit_man,pos_x,pos_y,station_type_name
            FROM itf_n9_exch d
           WHERE NOT EXISTS (SELECT 1 FROM itf_zytb_exch WHERE id = d.id)';
 

因此,验证的结果初步认为,对于insert append语句,如是该语句为动态的则必须在insert后执行commit方可继续对该表执行读写操作。

   7、子过程。如果一个过程只被调用一次,那么将该过程作为调用此过程的子过程。

   8、写过程要注意事务,什么情况下执行提交(如果出现ddl语句,默认的提交会将之前没提交的数据都提交,因此注意用自治事务的方式处理ddl语句)

   9、尽可能考虑程序中可能出现的各种例外。

原文地址:https://www.cnblogs.com/lanzi/p/2051429.html