1. --触发器
  2. drop table emp_log
  3. create table emp_log(
  4. empno number,
  5. log_date date,
  6. new_salary number,
  7. action varchar2(20) --动作记录
  8. );
  9. create or replace trigger log_sal_adj
  10. after update of sal on emp --指定当update执行后,监控对empsal列的更改 before or adter
  11. for each row --每update一行执行一次触发器代码
  12. declare
  13. v_action varchar2(20); --定义一个保存更新行为的字符串变量
  14. begin
  15. if :old.sal >:new.sal THEN
  16. v_action :='减少工资';
  17. elsif :old.sal<:new.sal then
  18. v_action :='增加工资';
  19. end if;
  20. insert into emp_log
  21. (empno,log_date,new_salary,action)
  22. values
  23. (:new.empno,sysdate,:new.sal,v_action);
  24. end;
  25. select * from emp_log;
  26. select sal from emp where empno=7369;
  27. update emp set sal=8000 where empno=7369;
  28. --异常处理示例
  29. declare
  30. v_result number:=0;
  31. v_dividend number:=&a; --定义替换变量
  32. begin
  33. v_result:=round(1000/v_dividend,2);
  34. dbms_output.put_line('结果值为:'||v_result);
  35. exception
  36. when zero_divide then --如果是被0除错误
  37. dbms_output.put_line('出现被0除的错误了!');
  38. when others then --所有其他错误的异常处理句柄
  39. dbms_output.put_line(sqlcode); --输出错误代码
  40. dbms_output.put_line(sqlerrm); --输出错误消息
  41. end;
  42. --记录类型示例
  43. Declare
  44. type emp_rec_type is record(
  45. empno emp.empno%type,
  46. ename varchar2(50),
  47. job varchar2(20) );
  48. emp_info_rec emp_rec_type;
  49. emp_row_rec emp%Rowtype; --=>(eno emp.empno%type +enme emp.ename%type)
  50. begin
  51. emp_info_rec.empno:=8222;
  52. emp_info_rec.ename:='李三思';
  53. emp_info_rec.job :='销售人员';
  54. insert into emp (empno,ename,job)
  55. values (emp_info_rec.empno,emp_info_rec.ename,emp_info_rec.job);
  56. select * into emp_row_rec from emp where empno=8222;
  57. dbms_output.put_line('新插入的员工记录信息:'||CHR(10)||'工号:'||
  58. emp_row_rec.empno||CHR(10)||'姓名:'||
  59. emp_row_rec.ename||CHR(10)||'职位:'||
  60. emp_row_rec.job);
  61. end;
  62.  
  63. --集合类型使用示例
  64. declare
  65. --定义保存员工工号的索引表,其类型为emp表中的empno字段相同的类型
  66. type NumTab is table of emp.empno%type index by binary_integer; --pls_integer
  67. type NameTab is table of emp.ename%type index by binary_integer;
  68. --定义集合类型的变量
  69. enums NumTab;
  70. names NameTab;
  71.  
  72. /* 定义块 type语句定义了NumTab和NameTab这两个索引表,
  73. is table of指定索引的类型, index by指定索引的下标数据类型
  74. binary_integer是PL/SQL中的整数类型
  75.  
  76. 匿名块print_first_n,它的作用范围仅限于匿名块内部
  77. 执行 select..bulk collect into将表中查询出来的多行记录写入到集合中
  78. */
  79. procedure print_first_n(n POSITIVE) is
  80. BEGIN
  81. IF enums.count =0 then
  82. DBMS_OUTPUT.put_line('当前集合为空!');
  83. else
  84. DBMS_OUTPUT.put_line('前'||n||'名员工:');
  85. for i in 1..n loop
  86. dbms_output.put_line('员工工号:'||enums(i)||': '||names(i));
  87. end loop;
  88. end if;
  89. END;
  90.  
  91. begin
  92. select empno,ename bulk collect
  93. into enums,names from emp
  94. order by empno;
  95. print_first_n(3);
  96. print_first_n(6);
  97. end;
  98.  
  99. select empno,ename from emp order by empno;
  100.  
  101. --使用游标遍历结果集
  102. declare
  103. emprow emp%rowtype;
  104. cursor emp_cur
  105. is
  106. select * from emp where deptno=20;
  107. begin
  108. open emp_cur;
  109. loop
  110. fetch emp_cur
  111. into emprow;
  112. DBMS_OUTPUT.put_line('员工编号:'||emprow.empno||' '
  113. ||'员工名称:'||emprow.ename);
  114. exit when emp_cur%NOTFOUND;
  115. end loop;
  116. close emp_cur; --关闭游标
  117. end;
  118.  
  119. 1 emprow是一个记录类型,保存fetch语句提取的记录值
  120. 2 cursor is 指向一个返回结果集的select语句
  121. 3 open语句打开游标,指向结果集内存区域
  122. 4 游标使用完之后,必须显示调用close关闭游标,释放资源
  123.  
  124. 子程序不像匿名块仅仅是一次使用,子程序存储在数据字典中
  125. 可以被其它子程序重复调用
  126.  
  127. --使用游标和索引表显示员工名称
  128. DECLARE
  129. --定义员工名称索引表
  130. TYPE emp_table IS TABLE OF VARCHAR2(10);
  131. emplist emp_table; --定义表类型的变量
  132. CURSOR empcursor IS
  133. SELECT ename FROM emp;
  134. BEGIN
  135. IF NOT empcursor%ISOPEN THEN
  136. OPEN empcursor;
  137. END IF;
  138. FETCH empcursor BULK COLLECT
  139. INTO emplist;
  140. FOR i IN 1 .. emplist.COUNT LOOP
  141. DBMS_OUTPUT.put_line('员工名称:' || emplist(i));
  142. END LOOP;
  143. CLOSE empcursor;
  144. END;
  145. --rowid使用示例
  146. declare
  147. v_empname rowid;
  148. v_other varchar2(18);
  149. begin
  150. select rowid into v_empname from emp where empno=&empno;
  151. dbms_output.put_line(v_empname);
  152. v_other:=rowidtochar(v_empname);
  153. dbms_output.put_line(v_other);
  154. end;
  155.  
  156. select rowid from emp where empno=7369;
  157.  
  158. --批量提取游标数据
  159. DECLARE
  160. type depttab_type is table of dept%rowtype;
  161. depttab depttab_type;
  162. cursor deptcur is select * from dept;
  163. begin
  164. open deptcur;
  165. fetch deptcur bulk collect into depttab;
  166.  
  167. for i in 1 .. depttab.count
  168. loop
  169. dbms_output.put_line(depttab (i).deptno ||' '||depttab(i).dname||' '||depttab(i).loc);
  170. end loop;
  171. close deptcur;
  172. end;
  173.  
  174. --操纵游标数据 loop循环
  175. declare
  176. dept_row dept%rowtype;
  177. cursor dept_cursor is select * from dept;
  178. begin
  179. open dept_cursor;
  180. loop
  181. fetch dept_cursor into dept_row;
  182. exit when dept_cursor%notfound;
  183. dbms_output.put_line('部门名称:'||dept_row.dname);
  184. end loop;
  185. close dept_cursor;
  186. end;
  187.  
  188. --while循环
  189. declare
  190. dept_row dept%rowtype;
  191. cursor dept_cursor is select * from dept;
  192. begin
  193. open dept_cursor;
  194. fetch dept_cursor into dept_row;
  195. while dept_cursor%found loop
  196. dbms_output.put_line('部门名称:'||dept_row.dname);
  197. fetch dept_cursor into dept_row;
  198. end loop;
  199. close dept_cursor;
  200. end;
  201. 调用了2fetch语句, 判断之前fetch一次获取%found属性值
  202. 后面的fetch语句在循环体内对每一次的循环求值
  203.  
  204. /*游标for循环 尽管定义为一个显式游标,但PLSQL引擎进行特别处理
  205. 不需要open,close;*/
  206. declare
  207. cursor dept_cursor is select * from dept;
  208. begin
  209. for dept_row in dept_cursor loop
  210. dbms_output.put_line('部门名称:'||dept_row.dname);
  211. end loop;
  212. end;
  213.  
  214. --游标FOR循环子查询语句
  215. begin
  216. for dept_row in (select * from dept) loop
  217. dbms_output.put_line('部门名称:'||dept_row.dname);
  218. end loop;
  219. end;
  220.  
  221. --使用游标更新数据
  222. declare
  223. cursor emp_cursor(p_deptno in number)
  224. is select * from emp where deptno=p_deptno for update;
  225. --使用for update子句添加互斥锁
  226. begin
  227. for emp_row in emp_cursor(20)
  228. loop
  229. update emp set sal=sal*1.12
  230. where current of emp_cursor;
  231. end loop;
  232. commit;
  233. end;
  234.  
  235. select sal,ename from emp where deptno=20;
  236.  
  237. --使用游标删除数据
  238. declare
  239. cursor emp_cursor(p_empno in number)
  240. is select * from emp_copy where empno=p_empno for update;
  241. begin
  242. for emp_row in emp_cursor(7369)
  243. loop
  244. delete from emp_copy where current of emp_cursor;
  245. end loop;
  246. end;
  247.  
  248. --游标变量
  249. declare
  250. type emp_type is ref cursor return emp%rowtype;
  251. emp_cur emp_type;
  252. emP_row emp%rowtype;
  253. begin
  254. open emp_cur for select * from emp;
  255. loop
  256. fetch emp_cur into emp_row;
  257. exit when emp_cur%notfound;
  258. dbms_output.put_line('员工名称:'|| emp_row.ename);
  259. end loop;
  260. end;
  261.  
  262. 11.14
  263. --使用close 语句关闭游标变量
  264. --如果type语句中未指定return子句,则可以连续地打开多次,分别为其赋不同的select语句
  265. declare
  266. type emp_type is ref cursor return emp%rowtype;
  267. emp_cur emp_type;
  268. emp_row emp%rowtype;
  269. begin
  270. open emp_cur for select * from emp where deptno=20;
  271. fetch emp_cur into emp_row;
  272. while emp_cur%found loop
  273. dbms_output.put_line('员工名称:'||emp_row.ename);
  274. fetch emp_cur into emp_row;
  275. end loop;
  276. close emp_cur;
  277. end;
  278.  
  279. 关闭一个还没有打开过的游标变量或已经关闭了的游标变量是非法的
  280. PLSQL引发invalid_cursor异常
  281. declare
  282. type emp_curtype is ref cursor;
  283. emp_cur1 emp_curtype;
  284. emp_cur2 emp_curtype;
  285. emp_row emp%rowtype;
  286. begin
  287. open emp_cur1 for select * from emp where deptno=20;
  288. fetch emp_cur1 into emp_row;
  289. dbms_output.put_line('员工名称:'||emp_row.ename||'部门编号:'
  290. ||emp_row.deptno);
  291. fetch emp_cur2 into emp_row;
  292. exception
  293. when invalid_cursor then
  294. emp_cur2:=emp_cur1;
  295. fetch emp_cur2 into emp_row;
  296. dbms_output.put_line('员工名称:' ||emp_row.ename||
  297. '部门编号:'||emp_row.deptno);
  298. --重新打开emp_cur2游标变量,利用相同的查询区域
  299. open emp_cur2 for select * from emp where deptno=40;
  300. fetch emp_cur1 into emp_row;
  301. --emp_cur1emp_cur2共享相同的查询区域,因此结果相同
  302. dbms_output.put_line('员工名称:' ||emp_row.ename||
  303. '部门编号:'||emp_row.deptno);
  304. end;
  305.  
  306. 使用open for语句打开emp_cur2时候,将相同的查询区域执行另一个查询语句
  307. 由于emp_cur1emp_cur2都指向相同的查询区域,提取emp_cur1时候
  308. 实际相当于对emp_cur2提取
  309. --处理ROWTYPE_MISMATCH异常
  310. declare
  311. type emp_curtype is ref cursor;
  312. emp_cur emp_curtype;
  313. emp_row emp%rowtype;
  314. dept_row dept%rowtype;
  315. begin
  316. open emp_cur for select * from emp where deptno=20;
  317. fetch emp_cur into dept_row;
  318. exception
  319. when rowtype_mismatch then
  320. fetch emp_cur into emp_row;
  321. dbms_output.put_line('员工名称:'||emp_row.ename
  322. ||'部门编号:'||emp_row.deptno);
  323. end;
  324. --使用sys_refcursor类型 不需要type语句显式定义弱类型游标
  325. declare
  326. emp_cur sys_refcursor; --定义弱类型游标变量
  327. emp_row emp%rowtype;
  328. dept_row dept%rowtype;
  329. begin
  330. open emp_cur for select * from emp where deptno=20;
  331. fetch emp_cur into dept_row;
  332. exception
  333. when rowtype_mismatch then
  334. fetch emp_cur into emp_row;
  335. dbms_output.put_line('员工名称:'||emp_row.ename
  336. ||'部门编号:'||emp_row.deptno);
  337. end;
  338. --在包中使用游标变量
  339. create or replace package emp_data_action as
  340. type emp_type is ref cursor return emp%rowtype; --定义强类型游标
  341. procedure getempbydeptno(emp_cur in out emp_type,p_deptno number);
  342. end emp_data_action;
  343.  
  344. create or replace package body emp_data_action as
  345. procedure getempbydeptno(emp_cur in out emp_type,p_deptno number)
  346. is emp_row emp%rowtype;
  347. begin
  348. open emp_cur for select * from emp where deptno=p_deptno;
  349. loop
  350. fetch emp_cur into emp_row;
  351. exit when emp_cur%notfound;
  352. dbms_output.put_line('员工名称:'||emp_row.ename
  353. ||'部门编号:'||emp_row.deptno);
  354. end loop;
  355. close emp_cur;
  356. end;
  357. end emp_data_action;
  358.  
  359. declare
  360. emp_cursors emp_data_action.emp_type;
  361. begin
  362. emp_data_action.getempbydeptno(emp_cursors,20);
  363. end;
  364.  
  365. 游标变量的限制
  366. 1.不能在包中声明游标变量
  367. 2 不能在创建表或创建视图的语句中把字段类型指定为REF CURSOR类型
  368. 数据库字段不能存放游标变量值
  369. 3 游标类型参数不支持远程过程调用
  370. 4 不能将ref cursor 类型作为集合的元素类型
  371. 5 不能在游标中使用游标for循环
  372. 一个事务必须满足ACID 即原子性,一致性,隔离性和持久性
  373. --使用保存点局部回滚
  374. declare
  375. dept_no number(2) :=90;
  376. begin
  377. savepoint A;
  378. insert into dept values(dept_no,'市场部','北京');
  379. savepoint B;
  380. insert into emp values(7997,'威尔','销售人员',null,trunc(sysdate),5000,300,dept_no);
  381. savepoint c;
  382. insert into dept values(dept_no,'后勤部','上海'); --插入相同编号的部门记录
  383. commit;
  384. exception
  385. when dup_val_on_index then
  386. dbms_output.put_line(sqlerrm);
  387. rollback to b;
  388. end;
  389.  
  390. select * from dept;
  391. --控制触发顺序 FOLLOWS子句
  392. create or replace trigger one_trigger
  393. before insert on trigger_data for EACH ROW
  394. begin
  395. :new.trigger_id := :new.trigger_id+1;
  396. DBMS_OUTPUT.put_line('触发了one_trigger');
  397. end;
  398.  
  399. create or replace trigger two_trigger
  400. before insert on trigger_data
  401. for each row follows one_trigger --让该触发器在one_trigger后面触发
  402. begin
  403. DBMS_OUTPUT.put_line('触发了two_trigger');
  404. if :new.trigger_id>1
  405. then
  406. :new.trigger_id := :new.trigger_id +2:
  407. end if;
  408. end;
  409.  
  410. --系统触发器 scott
  411. create table created_log
  412. (
  413. obj_owner varchar2(30),
  414. obj_name varchar2(30),
  415. obj_type varchar2(20),
  416. obj_user varchar2(30),
  417. created_date DATE
  418. )
  419. --system
  420. create or replace trigger t_created_log
  421. after create on scott.SCHEMA --在Scott方案下创建对象后触发
  422. begin
  423. insert into scott.created_log(obj_owner,obj_name,obj_type,obj_user,
  424. created_date) values (sys.dictionary_obj_owner,sys.dictionary_obj_name,
  425. sys.dictionary_obj_type,sys.login_user,sysdate);
  426. end;
  427. --scott
  428. create table temp_table(field1 varchar2(20),field2 number(5));
  429. select * from created_log;
  430. 触发器属性列表 6
  431. --ora_is_drop_columnora_is_alter_column 禁止非法更改列
  432. create or replace trigger preserve_app_cols
  433. after alter on schema
  434. declare
  435. cursor curs_get_columns (cp_owner varchar2,cp_table varchar2)
  436. is select column_name from all_tab_columns
  437. where owner = cp_owner and table_name=cp_table;
  438. begin
  439. if ora_dict_obj_type ='TABLE'
  440. THEN
  441. FOR v_column_rec in curs_get_columns (ora_dict_obj_owner,ora_dict_obj_name)
  442. loop
  443. if ora_is_drop_column(v_column_rec.column_name)
  444. then
  445. if v_column_rec.column_name='EMPNO' THEN
  446. RAISE_APPLICATION_ERROR(-2003,'不能对empno字段进行修改');
  447. end if;
  448. end if;
  449. end loop;
  450. end if;
  451. end;
  452. alter table emp drop column empno
  453. select * from emp;

PLSQL触发器,游标的更多相关文章

  1. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

      PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语 ...

  2. oracle(sql)基础篇系列(五)——PLSQL、游标、存储过程、触发器

    PL/SQL PL/SQL 简介 每一种数据库都有这样的一种语言,PL/SQL 是在Oracle里面的一种编程语言,在Oracle内部使用的编程语言.我们知道SQL语言是没有分支和循环的,而PL语言是 ...

  3. SQL SERVER触发器游标小记

    今天接到个需求用触发器来实现通过条件对其他表的更新.好久没摸SQL SERVER,电脑里也没SQL SERVER安装包,同事遂发来个安装包,一看吓一跳,3.6G!!!!经过漫长等待后,开始作业.需求如 ...

  4. sql 触发器 游标

    在数据库中,删除一条记录的同时想要删除另一个表里的数据,这时我们可以选择使用触发器.触发器主要是通过事件进行触发被自动调用执行的,而存储过程可以通过存储过程的名称被调用.触发器是当对某一个表进行操作. ...

  5. 2018.5.30 Oracle数据库PLSQL编程---游标的使用

    显示游标的步骤 /* 显示游标处理步骤 1.声明游标 语法结构:cursor 游标名称 is SQL 语句; 2.打开游标 语法结构:open游标名称; 3.提取数据 语法结构:fetch 4.关闭游 ...

  6. Oracle plsql 触发器 查询/启用/停止

    在PLSQL中查询某个表的触发器脚本 select * from user_triggers where table_name='xxx' oracle触发器的启用和停用 1.禁用 table_nam ...

  7. PLSQL触发器

    触发器权限 数据库创建用户时想要在本用户下使用触发器,需要给用户触发器的权限 使用DBA用户执行  GRANT CREATE TRIGGER TO user_name; 如果想在当前用户下创建其他用户 ...

  8. .Net程序员学用Oracle系列(27):PLSQL 之游标、异常和事务

    1.游标 1.1.游标属性 1.2.隐式游标 1.3.游标处理及案例 2.异常 2.1.异常类别 2.2.异常函数 2.3.异常处理及案例 3.事务 3.1.开始事务.结束事务 3.2.自治事务 3. ...

  9. SQL记录-PLSQL触发器

    PL/SQL触发器 触发器是存储程序,它会自动执行或发射当一些事件发生.触发器,事实上,写入响应于以下任一事件将被执行: 数据库操作(DML)语句(DELETE,INSERT,UPDATE或) 数据库 ...

随机推荐

  1. jquery环形3D立体旋转特效

      jquery环形3D立体旋转特效 作者/代码整理:站长素材  (转载请附加本文地址,带有“懒人原生”字样的谢绝转载)发布日期:2013-07-20   立体效果比较强的jquery特效,周围小图组 ...

  2. Spring常用jar包的功能

    jar名称 描述 spring-framework.jar spring框架比较完整的功能,core+aop+ioc+transaction spring-core.jar 基本上的核心工具类,一些u ...

  3. P3694 邦邦的大合唱站队

    题目背景 BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题. 题目描述 N个偶像排成一列,他们来自M个不同的乐队.每个团队至少有一个偶像. 现在要求重新安排队列,使来自同一 ...

  4. 随手练——Uva-11584 划分成回文串(区间DP)

    思路:dp[i]代表到第i位的最小值,枚举它的前几位,求出最小值. 转移方程:dp[ i ] = min(dp[ i ], dp[ j - 1 ] + 1 ) ; 本来觉得,代码加深部分可以提前bre ...

  5. 调试cnn-Sentence-Classifier遇到的问题

    运行train文件训练模型出现了以下错误: train文件在app文件目录下: raw_vectors.txt文件则在cnn-Sentence-Classifier目录下: 这是train代码调用re ...

  6. (转)使用 Nmon 监控 Linux 的系统性能

    看到一个使用Nmon的文章,写的很基础,适合新手,转载之.下面是原文的信息: 作者:Hitesh Jethva 译者:sonofelice 校对:wxy 传送门:linux.cn/article-68 ...

  7. 使用Android的OpenGL编写视频播放器

    Android自身有MediaPlayer播放器,为什么还要使用OpenGL?因为使用OpenGL可以实现更多的效果,比如对视频翻转一定角度,加任意特效,多视频合并播放等,类似“激萌”的APP应该就是 ...

  8. QoS policy-map class-map

    QoS(Quality of ServiceQoS(Quality of Service,服务质量)指一个网络能够利用各种基础技术,为指定的网络通信提供更好的服务能力, 是网络的一种安全机制, 是用来 ...

  9. 把外置sd卡映射为内置sd卡地一个目录

    教程:1.已root机器运行re浏览器2.在/sdcard卡上创建目录sd-ext3.找到/etc/rc.local,长按选编辑4.拉到文件最后,在最后一行exit 0前行添加:     (sleep ...

  10. 《Effective C++》item25:考虑写出一个不抛异常的swap函数

    std::swap()是个很有用的函数,它可以用来交换两个变量的值,包括用户自定义的类型,只要类型支持copying操作,尤其是在STL中使用的很多,例如: int main(int argc, _T ...