oracle 存储过程 与 触发器

存储过程是一组为了完成特定功能的sql语句,存储在数据库中,数据库开发人员经常会用到存储过程,
存储过程能够反复使用,减少开发人员工作量。

为什么要写存储过程

1.效率高
2.降低网络流量
3.复用性高
4.可维护性高
5.安全性高

存储过程示例:

CREATE OR REPLACE PROCEDURE demo AS/IS
	变量2 DATE;
	变量3 NUMBER;
BEGIN
	--要处理的业务逻辑
	EXCEPTION    --存储过程异常
-------------------
CREATE OR REPLACE PROCEDURE 存储过程名称(
       s_no in varchar,
       s_name out varchar,
       s_age number) AS
total NUMBER := 0;
BEGIN
  SELECT COUNT(1) INTO total FROM student s WHERE s.age=s_age;
  dbms_output.put_line('符合该年龄的学生有'||total||'人');
  EXCEPTION
    WHEN too_many_rows THEN 
    DBMS_OUTPUT.PUT_LINE('返回值多于1行'); 

存储过程语法

1:运算符:
算术运算符 + - * /
关系运算符  < >  = 
比较运算符 LIKE  BETWEEN in  is null 
逻辑运算符 and or not 
2:SELECT INTO STATEMENT语句 :
--给多个变量赋值
  SELECT student_name,student_age INTO s_name,s_age
  FROM student where student_grade=100;
3:选择语句 a.IF..END IF
IF s_sex=1 THEN
  dbms_output.put_line('这个学生是男生');
END IF
------
IF..ELSE..END IF
4:循环语句
  IF 表达式 THEN
    EXIT;
  END IF
END LOOP;
------
while 循环
WHILE 表达式 LOOP
  dbms_output.put_line('haha');
END LOOP;
for 循环
FOR a in 10 .. 20 LOOP
  dbms_output.put_line('value of a: ' || a);
END LOOP;

触发器

触发器(trigger)是数据库提供给程序员和数据分析员来保证数据完整性的一种方法,
它是与表事件相关的特殊的存储过程。由事件触发。
ORACLE触发器有三种类型,分别是:DML触发器、替代触发器和系统触发器。
创建触发器:
CREATE [OR REPLACE] TRIGGER trigger_name
{BEFORE | AFTER }
{INSERT | DELETE | UPDATE [OF column [, column …]]}
[OR {INSERT | DELETE | UPDATE [OF column [, column …]]}...]
ON [schema.]table_name | [schema.]view_name 
[REFERENCING {OLD [AS] old | NEW [AS] new| PARENT as parent}]
[FOR EACH ROW ]
[WHEN condition]
PL/SQL_BLOCK | CALL procedure_name;

示例:建立一个触发器, 当职工表 emp 表被删除一条记录时,把被删除记录写到职工表删除日志表中去。

CREATE TABLE emp_his AS SELECT * FROM EMP WHERE 1=2; 
CREATE OR REPLACE TRIGGER tr_del_emp 
   BEFORE DELETE --指定触发时机为删除操作前触发
   ON scott.emp 
   FOR EACH ROW   --说明创建的是行级触发器 
BEGIN
   --将修改前数据插入到日志记录表 del_emp ,以供监督使用。
   INSERT INTO emp_his(deptno , empno, ename , job ,mgr , sal , comm , hiredate )
       VALUES( :old.deptno, :old.empno, :old.ename , :old.job,:old.mgr, :old.sal,
 :old.comm, :old.hiredate );
DELETE emp WHERE empno=7788;

限制对Departments表修改(包括INSERT,DELETE,UPDATE)的时间范围,即不允许在非工作时间修改departments表。

CREATE OR REPLACE TRIGGER tr_dept_time
BEFORE INSERT OR DELETE OR UPDATE 
ON departments
BEGIN
 IF (TO_CHAR(sysdate,'DAY') IN ('星期六', '星期日')) OR (TO_CHAR(sysdate, 'HH24:MI')
 NOT BETWEEN '08:30' AND '18:00') THEN
     RAISE_APPLICATION_ERROR(-20001, '不是上班时间,不能修改departments表');
 END IF;
END;

存储过程:示例

CREATE OR REPLACE PROCEDURE P_T_AS_D_ITEM_DATA_TB_D_TEST1 AS
  V_ITEM1         VARCHAR2(50); ---时间当前
  V_ITEM2         VARCHAR2(50);
  V_TIME_ID       VARCHAR2(30); ---当前时间(换算过后的标准时间)
  V_TIME_ID_MONTH VARCHAR2(30); ---当前月对应的第一天
  V_TIME_ID_YEAR  VARCHAR2(30);
  V_LOB_UNIT      CLOB;
  V_TIME_ID1      VARCHAR2(30);
  REPORT_TYPE     VARCHAR(50);
  REPORT_NAME     VARCHAR(50);
  V_ID            VARCHAR(50);
  V_DATE          VARCHAR2(30);
  CONT1           NUMBER;
  CONT2           NUMBER;
  CONT3           NUMBER;
BEGIN
  V_DATE := TO_CHAR(SYSDATE, 'yyyymmdd');
  V_ITEM1 := V_DATE;
  V_ITEM2 := '6' || V_ITEM1;
  SELECT TO_CHAR(SYSTIMESTAMP, 'yyyymmddhh24missffyymmddhh24miss')
    INTO V_ID
    FROM DUAL;
  ------当前日期
  SELECT SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2)
    INTO V_TIME_ID
    FROM D_PUBLICINFO_TIME S
   WHERE SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2) = V_ITEM1;
  DBMS_OUTPUT.PUT_LINE(V_TIME_ID);
  ------当前日期(长时间)
  SELECT S.TIMEID
    INTO V_TIME_ID1
    FROM D_PUBLICINFO_TIME S
   WHERE SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2) = V_ITEM1;
  ------月的第一天
  SELECT SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2)
    INTO V_TIME_ID_MONTH
    FROM D_PUBLICINFO_TIME S
   WHERE SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2) = SUBSTR(V_ITEM1, 1, 6) || '01';
  DBMS_OUTPUT.PUT_LINE(V_TIME_ID_MONTH);
  ------当前年1月1号
  SELECT SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2)
    INTO V_TIME_ID_YEAR
    FROM D_PUBLICINFO_TIME S
   WHERE SUBSTR(S.TIMEID, 1, 4) || SUBSTR(S.TIMEID, 6, 2) ||
         SUBSTR(S.TIMEID, 10, 2) = SUBSTR(V_ITEM1, 1, 4) || '01' || '01';
  SELECT COUNT(*)
    INTO CONT1
    FROM T_DATA_INDEX@Lygs T
   WHERE T.TIMEID = V_TIME_ID1;
  SELECT COUNT(*)
    INTO CONT2
    FROM T_DATA_INDEX_LYDL T
   WHERE T.TIMEID = V_TIME_ID1;
  SELECT COUNT(*)
    INTO CONT3
    FROM T_AS_D_ITEM_DATA_TB@DBLINK_10_82_1_13_GDMQ T
   WHERE T.ISSUE = '6' || V_DATE;
  SELECT VALUE_TYPE, REPORT_SHORT_NAME
    INTO REPORT_TYPE, REPORT_NAME
    FROM T_ITEM_REPORT_CODE
   WHERE REPORT_CODE = 'S_D_YX_0_SCYXQK_1';
  DBMS_OUTPUT.PUT_LINE(CONT1);
  DBMS_OUTPUT.PUT_LINE(CONT2);
  IF CONT3 >= 15555 THEN
    INSERT INTO CS_1
      (SELECT '已完成', TO_CHAR(SYSDATE, 'YYYYMMDD HH24:MI:SS') FROM DUAL);
    COMMIT;
    IF CONT1 = CONT2 AND CONT1 = 0 THEN
      INSERT INTO CS_1
        (SELECT '未上报数据', TO_CHAR(SYSDATE, 'YYYYMMDD HH24:MI:SS')
           FROM DUAL);
      COMMIT;
      IF CONT1 != CONT2 THEN
        INSERT INTO CS_1
          (SELECT '数据不全', TO_CHAR(SYSDATE, 'YYYYMMDD HH24:MI:SS')
             FROM DUAL);
        COMMIT;
        IF CONT2 < 14943 THEN
          INSERT INTO CS_1
            (SELECT '数据不全', TO_CHAR(SYSDATE, 'YYYYMMDD HH24:MI:SS')
               FROM DUAL);
          COMMIT;
          IF CONT1 = CONT2 THEN
            INSERT INTO CS_1
            VALUES
              ('推送数据', TO_CHAR(SYSDATE, 'YYYYMMDD HH24:MI:SS'));
            COMMIT;
            /* SELECT '0' INTO conte1 FROM dual;
            --sys.dbms_lock.sleep(600);
            WHILE conte1 < '99999999' LOOP
              --sys.dbms_lock.sleep(60);
              SELECT conte1+1 INTO conte1 FROM dual;
              \*INSERT INTO CS_1 VALUES('中间库条数:'||conte1,TO_CHAR(SYSDATE,
'YYYYMMDD HH24:MI:SS'));
               COMMIT;*\
              END LOOP;*/
            --sys.dbms_lock.sleep(600);
             SELECT COUNT (*) INTO cont1 FROM t_data_index t
              WHERE t.timeid = V_TIME_ID1 ;
             SELECT COUNT(*) INTO cont2 FROM t_data_index@lygs t
              WHERE t.timeid = V_TIME_ID1;
            WHILE cont1 != cont2 LOOP
               SELECT COUNT (*) INTO cont1 FROM t_data_index t
                WHERE t.timeid = V_TIME_ID1 ;
                INSERT INTO CS_1 VALUES('中间库条数:'||cont1,TO_CHAR(SYSDATE,
'YYYYMMDD HH24:MI:SS'));
                  COMMIT;
              END LOOP;*/
            ------插入前删除当前数据
            DELETE FROM T_AS_D_ITEM_DATA_TB@DBLINK_10_82_1_13_GDMQ T
             WHERE T.ISSUE = '6' || V_ITEM1;
            COMMIT;
         V_LOB_UNIT := '
          INSERT INTO T_AS_D_ITEM_DATA_TB@DBLINK_10_82_1_13_GDMQ
          SELECT distinct
                 ' || V_ITEM2 ||
                                  ' AS ISSUE,
                 ''AS''|| d.indexid AS DEPT_ID,
                 D.jj,
                 T.ITEMCODE,
                 CASE WHEN T.thisvalue<0 THEN 0 ELSE t.thisvalue END AS ZBZ,
                   '''',
            FROM T_DATA_INDEX_LYDL T,
                 d_baseinfo_resource_xj D
           WHERE SUBSTR(T.TIMEID, 1, 4) || SUBSTR(T.TIMEID, 6, 2) || 
SUBSTR(T.TIMEID, 10, 2)= ' ||
                                  V_TIME_ID || '
                 AND T.TIMETYPEID = ''day''
                 AND T.CALIBERCODE = ''AS01''
                 AND T.RESOURCECODE = D.RESOURCECODE';
            --- DBMS_OUTPUT.PUT_LINE(V_LOB_UNIT);
            EXECUTE IMMEDIATE V_LOB_UNIT;
            COMMIT;
            /*   INSERT INTO t_generalinfo_reportlog_LY@DBLINK_10_82_1_13_GDMQ 
              VALUES
            (V_ID,
            :NEW.TIMEID,
            :NEW.TIMETYPEID,
            :NEW.RESOURCECODE,
            :NEW.REPORTCODE,
             REPORT_TYPE,
             REPORT_NAME,   
            :NEW.REPORTTIME
            COMMIT;*/
            INSERT INTO T_GENERALINFO_REPORTLOG_LY@DBLINK_10_82_1_13_GDMQ T
              (SELECT V_ID,
                      G.TIMEID,
                      G.TIMETYPEID,
                      G.RESOURCECODE,
                      G.REPORTCODE,
                      REPORT_TYPE,
                      REPORT_NAME,
                      G.REPORTTIME
                 FROM T_GENERALINFO_REPORTLOG G
                WHERE G.TIMEID = V_TIME_ID1);
            COMMIT;
            INSERT INTO CS_1
            VALUES
              ('当日数据推送完成', TO_CHAR(SYSDATE, 'YYYYMMDD HH24:MI:SS'));
            COMMIT;
            NULL;