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 );