zoukankan      html  css  js  c++  java
  • 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、尽可能考虑程序中可能出现的各种例外。

  • 相关阅读:
    mysql事务
    mysql函数
    mysql自连接
    MYSQL添加外键关联
    SQL多表查询
    SQL数据完整性
    SQL limit
    SQL分组查询
    升级GCC 6.2编译LLVM的问题
    Quartz时SLF4J错误
  • 原文地址:https://www.cnblogs.com/lanzi/p/2051429.html
Copyright © 2011-2022 走看看