1 select * from emp;
2
3 --分页查询
4 select rownum,empno from emp where rownum>0;
5 select * from(
6 select empno,rownum r from emp
7 )e where r>10 and r<13
8
9 ---PL/SQL入门--声明-type-rowtype-record-view-table
10
11 /*
12 PL/SQL语言
13 */
14
15 declare --定义部分
16 v_name varchar2(20);--变量的 声明: 变量名 变量类型
17 v_sal number(10,2);
18 begin--执行部分
19 v_name := 'lxm'; --变量
20 select ename ,sal into v_name,v_sal from emp where empno=&eno;--这里empno不写死的话,后边可以自己输入值
21 dbms_output.put_line(v_name||v_sal);
22 end;
23 select * from emp where empno=&eno;
24
25
26
27 /*
28 万能类型
29 将一个字段的类型作为一个数据类型
30 */
31 declare
32 v_name emp.job%type; --定义v_name的数据类型和emp里的job字段类型相同
33 begin
34
35 select job into v_name from emp where empno=7788;
36 dbms_output.put_line(v_name);
37 end;
38
39
40 /*
41 万能类型
42 将一行数据分别对应的类型作为一个打的数据类型
43 */
44 declare
45 v_rowdemo emp%rowtype; --定义变量的数据类型和emp整行的数据类型
46 --那么emp有几个字段,v_rowdemo就会有几个字段
47 begin
48 select * into v_rowdemo from emp where empno=7788;
49 dbms_output.put_line(v_rowdemo.ename||v_rowdemo.sal);--输出时使用变量.列名,直接输出整个变量会报错
50 end;
51
52
53
54
55 /*
56 record,是自己声明的一种一行多列的数据类型
57 使用一个变量,存储员工姓名和员工所在的部门名称
58
59 */
60
61 declare
62 --emp_info_record 是一个类型 相当于varchar
63 type emp_info_record is record(
64 v_ename varchar(30),
65 v_dname varchar2(30)
66 );
67 v_emp_info emp_info_record;
68 begin
69
70
71 /*
72 视图,
73 相当于一个虚表,查询结果被放在视图里。下次查东西可以直接从这里边查
74 scott默认没有创建视图的权限,所以要先以管理员身份登录给他赋权限
75 grant create view to scott
76 授权之后,scott用户就有了创建视图的权限
77 */
78 create view myview --create view 视图名
79 as
80 select empno,ename,sal from emp;
81 --视图创建成功,可以从其中查数据
82 select empno from myview
83
84
85 /*
86 %record
87 */
88 declare
89 type emp_record_type is record( --定义record
90 ename emp.ename%type,
91 sal emp.sal%type,
92 comm emp.comm%type,
93 total_sal emp.sal%type
94 );
95 v_emp_record emp_record_type; --声明一个record
96 begin
97 select ename,sal,nvl(comm,0),sal+nvl(comm,0) --执行查询
98 into v_emp_record
99 from emp where empno=7369;
100 dbms_output.put_line('姓名:'||v_emp_record.ename);
101 dbms_output.put_line('薪水:'||v_emp_record.sal);
102 dbms_output.put_line('奖金:'||v_emp_record.comm);
103 dbms_output.put_line('总薪水:'||v_emp_record.total_sal);
104 end;
105
106
107 /*
108 table数据类型
109 */
110 declare --定义一个table类型
111 type dept_table_type is table of dept%rowtype--type table名字 is table of table类型
112 index by binary_integer; --将主键定义为二进制
113 v_dept_table dept_table_type;
114 begin
115 select * into v_dept_table(0) from dept where deptno=10; --每次将一行主句赋值给table的另一行
116 select * into v_dept_table(1) from dept where deptno=20;
117 dbms_output.put_line('部门编号: '||v_dept_table(0).deptno||' 部门名称:'
118 ||v_dept_table(0).dname||' 位置:'||v_dept_table(0).loc);
119 dbms_output.put_line('部门编号: '||v_dept_table(1).deptno||' 部门名称:'
120 ||v_dept_table(1).dname||' 位置:'||v_dept_table(1).loc);
121 end;
122
123
124 /*
125 批量赋值
126 bulk:体积、大块
127 collect:搜集、收集
128 bulk collect into 相当于批量赋值
129 */
130 declare
131 type v_dept_table is table of dept%rowtype
132 index by binary_integer;
133 v_dept v_dept_table;
134 begin
135 --select * bulk collect into 表明 from 表名
136 select * bulk collect into v_dept from dept; --将所有的数据赋值给v_dept
137 dbms_output.put_line(v_dept(2).dname); --取的时候,取自己想要的
138 end;
139
140
141
142 --------------流程控制-----------------------
143 /*
144 if循环
145 相当于 if循环
146 if(n==5)
147 输出n
148
149 ---
150 if
151 条件1 then
152 执行语句1;
153 elsif 条件2 then
154 执行语句2;
155 else
156 执行语句;
157 end if;
158 */
159 declare
160 v_n number := 4;
161 begin
162 if v_n=5 then
163 dbms_output.put_line(v_n);
164 elsif v_n=4 then --注意oracle里没有else if,只有elsif,不要错误写成elseif
165 dbms_output.put_line('44444is'||v_n);
166 else
167 dbms_output.put_line('未知数');
168 end if;
169 end;
170
171
172
173 /*
174 case循环
175 case 变量
176 when 条件 then 执行语句;
177 when 条件 then 执行语句;
178 else 执行语句
179 end case
180 */
181
182 declare
183 v_deptno dept.deptno%type:=&deptno;
184 begin
185 case v_deptno
186 when 10 then dbms_output.put_line('我的部门是: '||v_deptno);
187 when 20 then dbms_output.put_line('我的部门是: '||v_deptno);
188 when 30 then dbms_output.put_line('我的部门是: '||v_deptno);
189 when 40 then dbms_output.put_line('我的部门是: '||v_deptno);
190 else dbms_output.put_line('不存在该部门');
191 end case;
192 end;
193
194
195 /*
196 loop循环
197 loop
198 [exit when 条件]
199 end loop;
200
201 相当于do while循环,先执行一次,再判断是否满足条件
202 */
203 declare
204 v_n number := 10;
205 begin
206 loop
207 v_n := v_n-1; --oracle中没有 v_n--;没有自减
208 dbms_output.put_line(v_n);
209 --exit when v_n=0;
210 if v_n=0 then exit;
211 end if;
212 end loop;
213 end;
214
215
216 /*
217 loop 循环和for循环嵌套
218 for n in 1..10表明n在[1,10]之间
219 reverse 表示降序排列,
220 */
221
222
223 begin
224 -- for n in 1..10
225 for n in reverse 1..10 --inverse代表逆序
226 loop
227 dbms_output.put_line(n);
228 end loop;
229 end;
230
231
232 /*
233 `相当于while循环
234 while 条件 loop
235 执行语句
236 end loop
237 */
238 declare
239 v_n number := 10;
240 begin
241 while v_n>0 loop
242 v_n := v_n-1;
243 dbms_output.put_line('n是: '||v_n);
244 end loop;
245 end;
246
247
248 --游标--
249 /*
250 定义游标:cursor 游标名字 is select_statement
251 打开游标:open 游标名字
252 提取游标数据:fetch 游标名字 into
253 关闭游标:close 游标名字
254
255 显式游标:处理select语句返回的多行数据
256 1):显示游标属性:
257 %ISOPEN:游标是否打开,打开为true,关闭为false
258 %FOUND:检查是否从结果集中提取到数据,提取到为true,没有提取到为false
259 %NOTFOUND:与%FOUND相反,此外 还可以用这个属性退出循环
260 %ROWCOUNT返回当前位置已经提取到的实际行数
261 属性使用方法 游标名+属性
262
263 2):带有参数的游标,多处使用游标,传入不同的参数时,获得不同的结果
264 cursor 游标名字 (参数名字,参数类型) is select_statement
265 定义时必须声明参数的数据类型,而不能定义参数的长度
266 隐式游标:用来处理select into 和DML语句
267 */
268
269 --显示游标
270 --eg1:
271 declare
272 v_dept dept%rowtype;
273 cursor cur_dept is select * from dept where deptno>10; --声明游标
274 begin
275 open cur_dept; --打开游标
276 loop
277 fetch cur_dept into v_dept; --提取数据
278 exit when cur_dept%NOTFOUND;
279 dbms_output.put_line('编号:'||v_dept.deptno||' 名字:'||v_dept.dname||' 位置:'||v_dept.loc);
280 end loop;
281 close cur_dept;
282 end;
283
284
285 --eg2:用table结构提取游标数据
286 declare
287 type v_dept is table of dept%rowtype
288 index by binary_integer; --声明表结构
289 cursor cur_dept is select * from dept;--声明游标
290 v_dept_table v_dept;--声明一个变量是v_dept类型的
291 begin
292 open cur_dept;
293 fetch cur_dept bulk collect into v_dept_table;--将游标中的数据批块放入到表里
294 close cur_dept; --数据已经拿到,就可以关闭游标
295 for i in v_dept_table.first..v_dept_table.last loop--遍历一个表结构就用 for in
296 dbms_output.put_line('位置:' ||v_dept_table(i).loc);--循环输出,就用下表
297 end loop;
298 end;
299
300 --eg3:带参数的游标
301 declare
302 cursor cur_dpet(para_deptno number) is --定义有参数的游标
303 select dname, loc from dept where deptno=para_deptno;--将参数作为查询条件
304 dept_record cur_dpet%rowtype; --定义一个变量,类型和游标的行类型一直
305 begin
306 open cur_dpet(20); --打开游标,同时把参数传进去
307 loop
308 fetch cur_dpet into dept_record; --提取数据,放到dept_record里
309 exit when cur_dpet%notfound;
310 dbms_output.put_line(dept_record.dname||' '||dept_record.loc);
311 end loop;
312 close cur_dpet; --关闭游标
313 end;
314
315
316
317 --eg4:for循环简化游标遍历,
318 --用for循环时,oracle会隐式打开游标并且提取数据后关闭,
319 declare
320 cursor cur_dept is select * from dept;
321 begin
322 for cur_row in cur_dept loop --n相当于游标中存储的数据,所对应的一个个的行数据的对象
323 dbms_output.put_line('行编号是'||cur_dept%rowcount||' 部门名字是:'||cur_row.dname);
324 end loop;
325 end;
326
327 --eg5:使用for循环时,游标可以更简化,声明、打开、关闭、都可以省略
328
329 begin
330 for dept_row in(select dname,loc from dept) loop
331 dbms_output.put_line('部门位置是--:'||dept_row.loc);
332 end loop;
333 end;
334
335 --游标变量--
336 /*
337 游标和游标变量的区别
338 1):游标是数据库中一个命名的工作区,与固定的SQL语句相关联,在编译时是已知的,
339 是静态的,永远指向一个相同的查询工作区
340 ---简而言之,对应的SELECT语句,在游标定义的时候,在declare声明部分就已经写好了
341 2):游标变量
342 A:语法
343 type ref_type_name IS REF CURSOR; --先定义一个游标变量
344 v_ref ref_type_name; 再声明一个变量,这个变量的类型是 上边定义好的游标变量的类型
345 B:游标变量在运行时可不同的SQL语句先关联,这样运行不同的SQL语句就可以引用不同的工作空间
346 */
347
348 --eg:游标变量
349 declare
350 type ref_type_name is ref cursor;--定义
351 cur_emp ref_type_name; --定义游标的类型,是个游标变量
352 v_row emp%rowtype; --后边用,用来存储游标中的一行数据
353 begin
354 open cur_emp for select * from emp where empno=7369; --open for ,打开
355 loop
356 fetch cur_emp into v_row ;
357 exit when cur_emp%notfound;
358 dbms_output.put_line('行号:'||cur_emp%rowcount||' 部门编号:'||v_row.empno||';部门名字:'||v_row.ename);
359 end loop;
360 end;
361
362 /*
363 隐式游标
364 跟显示游标不同的是,游标的定义,打开,数据提取,关闭,都是由数据库隐式来操作的
365 属性只有两个 SQL%FOUND, SQL%NOTFOUND
366 */
367
368 declare
369 v_empno number(10) := 7369;
370 begin
371 update emp set ename='小绿绿' where empno=v_empno;
372 if sql%found then --判断隐含游标sql是否有影响行数
373 dbms_output.put_line('修改成功');
374 else
375 dbms_output.put_line('修改失败,员工不存在');
376 end if;
377 end;
378
379
380 ------触发器---
381 /*
382 create or replace trigger 触发器名字
383 before[after]
384 事件[update or delete or insert]
385 on 表名
386
387 :new表和:old表
388 只有用了 for each row 才能用new ,old
389 new和old 相当于虚表
390 insert:新增,把新数据存到:new,再执行新增
391 delete:删除,把老数据存到:old,再执行删除
392 update:修改,把老数据存到:old,把新数据存到:new,判断:old和:new表中数据是否一样,
393 一样不执行任何修改,不一样执行修改
394
395 create or replace trigger 触发器名字
396 before[after] --触发时机
397 update [delete、insert、select]操作的动作
398 on 表名
399 for each row --没触发一行就触发一次 触发器
400 begin
401 if(updating) then
402 执行语句
403 end if;
404 end;
405 */
406 create or replace trigger tri_dept
407 after --触发时机,before为之前,after为之后
408 update or delete or insert --哪些事件会触发 触发器
409 on dept --对哪张表操作
410 for each row --每一行操作时都出发,如果不写,比如对整个表都进行修改,但只触发一次,
411 --写了这一句,sql语句设计到几行,就出发几次事件
412 begin
413 if(updating) then
414 dbms_output.put_line('你出发的操作是update旧数据是: '||:old.loc);--old是原表中的数据
415 dbms_output.put_line('你出发的操作是update新数据是: '||:new.loc);--new是修改后的新数据
416 end if;
417 if(deleting) then
418 dbms_output.put_line('触发器触发delete...');
419 end if;
420 if(inserting) then
421 dbms_output.put_line('触发器触发insert');
422 end if;
423 end;
424
425
426
427 --存储过程--procedure
428 /*
429 第一种 无参数的过程,
430
431 语法:
432 create or repalace procedure 名字
433 is
434 声明部分
435 begin
436 执行部分
437 exception
438 异常处理部分
439 end;
440 */
441
442 --一个没有exception的无参存储过程
443 create or replace procedure pro_emp_sal--注意这里,过程名字后边没有()
444 is
445 begin
446 update dept set loc='sahgnhai' where deptno = 20;--
447 end;
448
449 --一个有exception的无参存储过程
450 create or replace procedure pro_sel_sal
451 is
452 v_sal number(10);
453 begin
454 select sal into v_sal from emp where deptno=70;
455 dbms_output.put_line(v_sal);
456 exception
457 when no_data_found then
458 dbms_output.put_line('员工编号不存在');
459 end;
460
461 drop procedure pro_sel_sal; --删除 存储过程 drop procedure 过程名字
462 --调用无参过程的三种方法
463 call pro_sel_sal();--call 过程名字();
464 exec pro_emp_sal; --exec 过程名字; 但是这种方式只有再sqlplus 或者命令窗口中可以用,再plsql中不可以用
465 begin --begin 过程名字; end;
466 pro_sel_sal;
467 end;
468 select * from emp;
469 update dept set loc='aa' where deptno='40'
470
471
472 /*
473 有参的存储过程(如果不指定参数模式,默认为输入参数)
474
475 有三种参数形式:
476 1):in传参 ,定义被in,输入参数,这个in可以不写,默认就是输入传参
477 2):out传参,该参数是用来输出的
478 3):in out 传参 该参数既用来输入,也用来输出
479
480 有三种参数传递的形式
481 1):按照参数顺序依次放入参数
482 2):用=>传递参数 eg: pro_emp_sal(v_no=>'7369'); 注意,变量在前边,传过来的值在后边
483 3):混合方式传参,参数1,放在第一个位置,后边的参数用 =>传递参数
484 不管是哪种传参方式,被in,或者out,或者 inout修饰的参数,在调用的时候一定要声明
485 */
486
487 /*
488 in传参 创建存储过程
489 */
490 create or replace procedure pro_emp_sal(v_no in emp.empno%type)
491 is
492 v_sal number(10);
493 begin
494 select sal into v_sal from emp where empno=v_no;
495 dbms_output.put_line(v_no ||' 的工资是:'||v_sal);
496 exception
497 when no_data_found then
498 dbms_output.put_line('请输入正确的员工编号');
499 end;
500 --调用 存储过程
501 declare
502 v_no number(10);
503 begin
504 v_no := &empno;
505 pro_emp_sal(v_no);
506 end;
507
508
509 /*
510 out 传递参数的存储过程
511 */
512 create or replace procedure pro_sel_al(v_sal out emp.sal%type)
513 is
514 begin
515 select sal into v_sal from emp where empno=7369;
516 dbms_output.put_line(v_sal);
517 end;
518
519 --调用存储过程
520 declare
521 v_sals number(10);
522 begin
523 pro_sel_al(v_sal=>v_sals);-- =>传递参数
524 end;
525
526 /*
527 in,out分别传递参数,的存储过程
528 */
529 create or replace procedure pro_emp_sal(v_no in emp.empno%type, v_sal out emp.sal%type)
530 is
531 begin
532 select sal into v_sal from emp where empno=v_no;
533 dbms_output.put_line('工资是: '||v_sal);
534 end;
535
536 --调用 存储过程
537 declare
538 v_no emp.empno%type;
539 v_sal emp.sal%type;
540 begin
541 v_no := &no; --输入的变量一定要在执行的时候定义出输入
542 pro_emp_sal(v_no,v_sal); --按照参数位置传参
543
544 end;
545
546 /*
547 in out传递参数
548 在这里 in out 修饰同一个变量,则这个变量既是输入变量也是输出变量
549 */
550 create or replace procedure pro_emp_sal(empnum in out number)
551 is
552 begin
553 select sal into empnum from emp where empno=empnum;
554 -- dbms_output.put_line(v_no ||'的工资是: '|| empnum);
555 end;
556
557 --调用存储过程
558 declare
559 in_outnum emp.empno%type;
560 begin
561 in_outnum := &no;
562 pro_emp_sal(in_outnum);
563 dbms_output.put_line('工资是: '||in_outnum);
564 end;
565
566
567
568 ----开发函数----
569 /*
570 create or replace function 名字()
571 return 返回值类型; --一定要有的
572 is[as]
573 变量声明部分
574 begin
575 执行语句
576 return 语句; --一定要有
577 exception
578 end;
579 */
580
581 create or replace function getsum(m number , n number)
582 return number
583 is
584 mn number;
585 begin
586 mn := m+n;
587 return mn;
588 end;
589
590 --调用function
591 declare
592 m number;
593 n number;
594 mn number;
595 begin
596 m := &m;
597 n := &n;
598 mn := getsum(m,n);
599 dbms_output.put_line(mn);
600 end;
601
602 ---过程与函数的异同-------
603 /*
604 1:相同点
605 1):都用in模式传入数据,都用out模式传出数据
606 2):参数的传递都可以用位置传递法和名称传递法
607 3):输入参数时都可以有默认值,都可以传值
608 4):都有声明部分、执行部分、异常部分
609 2:不同点
610 1):没有返回值,或者只输出一个值时用function
611 2):输出多个值时用存储过程
612 3):输出多个值时也可以用function,但是这被认为是不规范的写作习惯
613 4):一般存储过程用来完成某个动作,function用来计算或者返回一个值
614 */
615 --包--
616 /*
617 包存在的意义:满足oracle种模块化的需求,在大型项目中,每个模块有很多的过程和函数,不便于管理和维护
618 甚至造成误删,所以分包后便于管理,
619 解决了命名的问题,不同包里的函数或者过程可以命名相同
620
621
622 包头--语法: --包头规范相当于java中的接口
623 create or replace package 包名 is
624 function 函数名() return 返回类型;
625 procedure 过程名();
626 end 包名;
627
628 包体--语法: --包体规范相当于java中的接口实现
629 create or replace package body 包名 is
630 写function; (这里直接写,没有create or replace 这句话)
631 写过程;(这里直接写,没有create or replace 这句话)
632 end 包名
633
634 --调用方法:
635 decalre
636 声明部分
637 begin
638 包名.函数名;
639 包名.过程名;
640 end;
641 */
642 --包头
643 create or replace package my_package is
644 function plus(m number, n number) return number;
645 procedure cheng(x number, y number, xy out number);
646 end my_package;
647
648 --包体
649 create or replace package body my_package is
650 function plus(m number, n number) return number
651 is nm number;
652 begin
653 nm := m+n;
654 return nm;
655 end;
656 procedure cheng(x number, y number, xy out number)
657 is
658 begin
659 xy := x+y;
660 dbms_output.put_line(xy);
661 end;
662 end my_package;
663 --调用包里的方法
664 declare
665 cc number(10);
666 begin
667 -- cc:= my_package.plus(11,22);
668 --dbms_output.put_line('两个数的和是:'||cc);
669 my_package.cheng(11,2,xy=>cc);
670 end;
671
672 /*
673 数据字典:user_source
674 跟用户相关的子程序和和源代码被存在里边
675 假如要查看 包名为my_package,的源代码
676 select text from user_source where name='my_package';
677 删除子程序 :drop procedure proce_anme
678 删除包体: drop package body 包名
679 删除包头和包体 drop pacakge 包名
680 */
681 select text from user_source where name='MY_PACKAGE';
682
683 --------游标--------
684
685 /*
686
687 1:游标是啥?
688
689 游标是指向上下文区的指针,它为应用提供了一种对具有多行查询结果集的数据,中
690
691 的每一行分别进行单独处理的方法
692
693 */
694
695 declare
696
697 v_dept dept%rowtype;
698
699 cursor dept_cursor is select * from dept where deptno>10; --定义游标
700
701 begin
702
703 open dept_cursor; --打开游标
704
705 loop
706
707 fetch dept_cursor into v_dept; --提取数据
708
709 exit when dept_cursor%notfound; --判断循环退出条件
710
711 dbms_output.put_line('编号:'||v_dept.deptno
712
713 ||' 名称:'||v_dept.dname||' 地址:'||v_dept.loc);
714
715 end loop;
716
717 close dept_cursor; --关闭游标
718
719 end;
720
721