1 /*
2 * PL/SQL -
3 * 是Oracle数据库特定的数据库编程语法.
4 * 所有的数据库存储过程/函数/触发器开发,都是数据库特定的语法.
5 * 第一代: 机器语言
6 * 第二代: 面向过程的语言
7 * 第三代: 面向对象的语言
8 * 第四代语言: 面向结果的语言. 语言编写完毕后,只要求结果正确.
9 *
10 * PL/SQL是在Oracle数据库管理系统中开发的语法.
11 * 是将有逻辑的SQL语句,固化在Oracle的DBMS中,可以重复调用的方式.
12 * 如: to_date() to_char() replace() substring() max() min() avg() upper()
13 */
14
15 /*
16 * Oracle数据库为了提高执行效率.默认是关闭手工输出流的.
17 * 开启手工输出:
18 * set serveroutput on;
19 * 关闭手工输出:
20 * set serveroutput off;
21 */
22 -- hello world
23 /*
24 * 执行存储过程/函数的方式
25 * 1. execute - 执行
26 * 2. call - 调用, call命令可能有缓存. 结果输出不是每次都能看到的.
27 * 必须刷新缓存或缓存空间不足的时候,才能看到结果
28 * 3. 匿名代码块, 只能执行唯一一次的存储过程/函数.
29 */
30 execute dbms_output.put_line('hello world');
31 call dbms_output.put_line('hello world with call');
32 begin
33 dbms_output.put_line('hello world with block');
34 end;
35 /
36
37 /*
38 * 匿名代码块结构及常用语法
39 * declare
40 * 定义变量
41 * 变量定义语法
42 * 变量名 变量类型;
43 * 变量定义并初始化语法 , := 赋值, = 比较等值 , > < >= <= != <>
44 * 变量名 变量类型 := 变量数据;
45 * begin
46 * 定义代码逻辑
47 * 变量赋值 - 变量名 := 值;
48 * 执行语法 - 语法;
49 * end;
50 */
51 -- 循环 loop
52 -- 1. loop循环, 天生就是无限循环
53 declare
54 v_i number := 1;
55 begin
56 loop -- 开始循环
57 dbms_output.put_line(v_i);
58 v_i := v_i + 1;
59 exit when v_i > 10; -- 当条件满足的时候,执行exit命令.
60 end loop; -- 结束循环
61 end ;
62 /
63
64 -- while loop循环
65 declare
66 v_i number := 1;
67 begin
68 while v_i < 11 loop -- 当条件满足的时候,循环
69 dbms_output.put_line(v_i);
70 v_i := v_i + 1;
71 end loop; -- 结束循环
72 end ;
73 /
74
75 -- for循环
76 begin
77 for v_i in reverse 1..10 loop -- 当变量v_i在范围1到10之间的时候,循环. for循环数据自增1
78 dbms_output.put_line(v_i);
79 end loop;
80 end ;
81 /
82
83 /*
84 * PL/SQL中的CRUD
85 */
86 -- insert
87 declare
88 v_id number := 2;
89 str varchar(32) := 'bbb';
90 age number := 30;
91 begin
92 -- insert into tb_temp(id, v_str, v_age) values(1, 'aaa', 20);
93 insert into tb_temp(id, v_str, v_age) values(v_id, str, age);
94 commit;
95 end ;
96 /
97
98 -- update
99 begin
100 update tb_temp
101 set v_str = 'ccc', v_age = 40
102 where id = 1;
103 commit;
104 end ;
105 /
106
107 -- delete
108 begin
109 delete from tb_temp where id = 2;
110 commit;
111 end ;
112 /
113
114 -- select, 要求将查询结果保存在变量中. 因为PL/SQL没有自动输出. 查询结果无保存单元.
115 -- 限制为只能查询一条数据
116 declare
117 v_id number;
118 str varchar2(32);
119 age number;
120 begin
121 select id, v_str, v_age into v_id, str, age from tb_temp;
122 dbms_output.put_line('id = ' || v_id || ', str = ' || str || ', age = ' || age);
123 end ;
124 /
125
126 -- cursor 游标, 用于处理查询的PL/SQL语法结构.
127 -- 类似java中的ResultSet. 在Oracle中是用来定位查询语句结果内存的一个引用.
128 /*
129 * 游标定义方式
130 * cursor 游标命名 is 查询语法;
131 * 游标属性
132 * 游标命名%found -- 最近一次fetch是否有结果, 无结果返回false,有结果返回true
133 * 游标命名%notfound -- 最近一次fetch是否有结果, 有结果返回false,无结果返回true
134 * 游标命名%isopen -- 是否开启. 已开启返回true
135 */
136 declare
137 cursor c_temp is select * from tb_temp;
138 begin
139 for v_temp in c_temp loop -- 变量v_temp的类型就是游标中的一行数据的类型.
140 dbms_output.put_line(v_temp.id || ' , ' || v_temp.v_str || ' , ' || v_temp.v_age);
141 end loop;
142 end ;
143 /
144
145 declare
146 cursor c_temp is select * from tb_temp;
147 v_temp tb_temp%rowtype; -- 变量v_temp和表格tb_temp中的一行数据的类型一样
148 begin
149 -- 开启游标
150 open c_temp;
151
152 -- 循环游标
153 loop
154 fetch c_temp into v_temp; -- 迭代游标中的一行数据到变量v_temp中.
155 exit when c_temp%notfound; -- %notfound是游标的属性,代表最近一次fetch是否有新的数据.
156 dbms_output.put_line(v_temp.id || ' , ' || v_temp.v_str || ' , ' || v_temp.v_age);
157 end loop;
158
159 -- 关闭游标
160 close c_temp;
161 end ;
162 /
163
164 declare
165 cursor c_temp is select * from tb_temp;
166 v_temp tb_temp%rowtype; -- 变量v_temp和表格tb_temp中的一行数据的类型一样
167 begin
168 -- 开启游标
169 open c_temp;
170
171 fetch c_temp into v_temp; -- 迭代游标中的一行数据到变量v_temp中.
172
173 -- 循环游标
174 while c_temp%found loop
175 dbms_output.put_line(v_temp.id || ' , ' || v_temp.v_str || ' , ' || v_temp.v_age);
176 fetch c_temp into v_temp; -- 迭代游标中的一行数据到变量v_temp中.
177 end loop;
178
179 -- 关闭游标
180 close c_temp;
181 end ;
182 /
183
184 /*
185 * 判断语法
186 * if xxx then
187 * end if;
188 * if xxx then
189 * end if;
190 * if xxx then
191 * elsif xxx then
192 * else
193 * end if;
194 */
195 declare
196 v_i number := 0;
197 begin
198 -- v_i > 0 输出正数, <0 输出负数, == 0输出零
199 if v_i > 0 then
200 dbms_output.put_line('正数');
201 elsif v_i < 0 then
202 dbms_output.put_line('负数');
203 else
204 dbms_output.put_line('零');
205 end if;
206 end ;
207 /
208
209 /*
210 * 存储过程 - procedure
211 * 创建存储过程,语法和创建表类似
212 * 存储定义逻辑和匿名代码块类似
213 * 没有返回值.
214 */
215 -- 定义
216 create procedure print(v_str varchar2) -- ()中定义参数, 参数只定义类型,不定义长度.
217 as -- 代替declare, as或is关键字不可少.
218 begin
219 dbms_output.put_line(v_str);
220 end;
221 /
222
223 -- 定义+重置
224 create or replace procedure print(v_str varchar2) -- ()中定义参数, 参数只定义类型,不定义长度.
225 as -- 代替declare, as或is关键字不可少.
226 begin
227 dbms_output.put_line(v_str);
228 end;
229 /
230
231 /*
232 * 查看存储过程定义的编译错误: show errors;
233 *
234 * 存储过程中的参数
235 * 在存储过程中,参数除有类型外,还有传递方向.
236 * 方向分为三种
237 * 1. 输入参数 - 默认参数方向, 代表参数数据只能读,不能写. 定义语法 : 参数名 [in] 参数类型
238 * 2. 输出参数 - 可以作为返回值的参数. 可写. 特性为, 第一次在存储过程中使用参数,格式化. 在使用的时候有要求
239 * 要求是,传入的输出参数必须是一个可复制的变量.不能是常量. 定义语法: 参数名 out 参数类型
240 * 3. 输入输出参数 - 可读可写. 不会格式化.语法: 参数名 in out 参数类型. 最不常用的参数方向.
241 * 数据库是一个弱类型的数据存储管理工具. 容易造成参数转化错误
242 */
243
244 create or replace procedure helloWorld(v_name in out varchar2)
245 as
246 begin
247 v_name := 'hello ' || v_name;
248 print(v_name);
249 end ;
250 /
251
252 create or replace procedure helloWorld(v_name out varchar2)
253 as
254 begin
255 v_name := 'hello ' || v_name;
256 print(v_name);
257 end ;
258 /
259
260 declare
261 v_name date := sysdate;
262 begin
263 print('调用helloWorld之前: ' || v_name);
264 helloWorld(v_name);
265 print('调用helloWorld之后: ' || v_name);
266 end ;
267 /
268
269 declare
270 v_name varchar2(32) := 'world';
271 begin
272 print('调用helloWorld之前: ' || v_name);
273 helloWorld(v_name);
274 print('调用helloWorld之后: ' || v_name);
275 end ;
276 /
277
278 create or replace procedure print(v_str in varchar2) -- ()中定义参数, 参数只定义类型,不定义长度.
279 as -- 代替declare, as或is关键字不可少.
280 begin
281 -- v_str := 'hello ' || v_str;
282 dbms_output.put_line(v_str);
283 end;
284 /
285
286
287 /*
288 * 函数 function
289 * 和存储过程之间的区别有:
290 * 1. 关键字不同
291 * 2. 有返回值
292 * 3. 调用函数和调用存储过程方式不同.
293 * 调用函数可以在SQL语法的DQL语句中使用.存储过程不能在DQL语句中使用.
294 * 函数调用的时候,可以使用变量接收函数的返回值. 存储过程不能.
295 */
296 create or replace function f_test(v_str varchar2)
297 return varchar2
298 as
299 begin
300 return 'hello ' || v_str;
301 end ;
302 /
303
304 declare
305 v_str varchar2(32);
306 begin
307 -- v_str := f_test('zhangsan');
308 -- print(v_str);
309 print(f_test('lisi'));
310 end ;
311 /
312
313 /*
314 * 触发器, trigger. 不推荐使用. 影响数据库管理系统的执行效率
315 * 触发器都是为表格提供的. 类似java中的监听器. 当某条件满足的时候,自动执行.
316 * 对表格的CUD操作.
317 * 通常触发器用于表中数据的保护.
318 * 如: ERP系统中的用户数据保护. 用户为系统持有者. 如: 京东.京东用户是京东的员工.
319 */
320
321 create or replace trigger ti_test1 before update on tb_temp
322 for each row -- 行级触发器. 当表中每行数据有CUD操作时触发.
323 when (old.id < 100) -- 当更新数据的id小于100的时候,触发器执行.
324 begin
325 dbms_output.put_line('before update触发器执行');
326
327 -- :old : 旧的数据.在更新和删除的时候存在.
328 dbms_output.put_line(:old.id || ' , ' || :old.v_str || ' , ' || :old.v_age);
329
330 -- :new : 新的数据.在新增和更新的时候存在.
331 dbms_output.put_line(:new.id || ' , ' || :new.v_str || ' , ' || :new.v_age);
332 end ;
333 /
334
335 create or replace trigger ti_test2 after update on tb_temp
336 begin
337 dbms_output.put_line('after update触发器执行');
338 end ;
339 /
340
341
342 -- 网络查询JDBC中的CallableStatement call xxxx();
343
344
345
346
347
348
349
350
351
352
353 create table tb_temp(
354 id number(8) primary key,
355 v_str varchar2(32),
356 v_age number(3)
357 );