【Oracle PLSQL】基础

一、PLSQL简介

  • PLSQL是一种程序语言,叫做过程化SQL语言(Procedural Language/SQL)
  • PLSQL是Oracle数据库对SQL语句的扩展。在普通SQL语句的使用上增加了编程语言的特点。
  • PLSQL是Oracle系统的核心语言,现在Oracle的许多部件都是由PLSQL
    写成的
  • PLSQL具有简单、高效、灵活、实用的特点
  • Oracle数据库对SQL 的扩展是PLSQL,SQL Server则是Transac-SQL(T-SQL)

PLSQL的官方文档地址:https://docs.oracle.com/cd/E11882_01/appdev.112/e25519/toc.htm

二、PLSQL语法结构

1.PLSQL块

块(block)是PLSQL的基本程序单位。由声明部分、执行部分、异常处理部分组成

DECLARE
	/*声明部分----声明变量、常量、复杂数据类型、游标等*/
BEGIN
	/*执行部分----PLSQL语句和SQL语句*/
EXCEPTION
	/*异常处理部分----处理运行错误*/
END;----块结束标记
	
2.PLSQL块的分类

匿名块:动态构造,只能执行一次。
子程序:存储在数据库中的存储过程、函数及包等。当在数据库上建立好后可以在其它程序中调用它们。
触发器:当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。
示例:(全文代码环境全部在navicat 查询界面)

BEGIN
	DBMS_OUTPUT.PUT_LINE('hello,word!');--打印语句
END;

三、PLSQL变量

1.命名规则

当编写PLSQL块时,为了临时存储数据,需要定义变量和常量,这些名称的定义需要满足一下规则:

  • 标识名不能超过30个字符
  • 第一个字符必须为字母
  • 不分大小写
  • 不能用“-”减号等特殊符号
  • 尽量不把变量名声明和表中字段名一样

参考规则(name是表名):

标识符 命名规则
程序变量 v_name
程序常量 c_name
游标变量 name_curror
异常标识 e_name
记录类型 name_record
2.变量类型
  • 数值类型:NUMBER(p,s)以及子类型INT、FLOAT等
  • 字符类型:CHAR(n)、VARCHAR2(n)
  • 日期类型:DATE
  • 布尔类型:BOOLEAN
3.大小写规则

当编写sql语句的PLSQL语句时,既可以采用大写格式,也可以采用小写格式。但是为了程序的可读性,应尽量按照以下规则:

  • SQL关键字采用大写格式,如:SELECT ,UPDATE等
  • PLSQL关键字采用大写格式,如:DECLARE, BEGIN, END等
  • 数据类型采用大写格式,如:INT, DATE等
  • 标识符采用小写格式,如:v_sal等
  • 数据库对象和列采用小写格式,如:emp,sal等
4.注释
  • 单行注释: --注释内容
  • 多行注释:/注释内容/
5.变量赋值

variable:=expression
如果在声明部分赋值,也可以使用DEFAULT关键字

6.示例
DECLARE
	v_name VARCHAR2(10);
	v_sal NUMBER(7,2);
	v_hiredate DATE;
	c_tax_rate CONSTANT NUMBER(3,2)= 0.02;--变量常量赋值,这里:=也可以用DEFAULT代替
	v_tax_sal NUMBER(7,2);
	v_valid BOOLEAN DEFAULT TRUE;--DEFAULT也可以用赋值符号:=代替,布尔类型变量主要勇士逻辑判断
	c_empno INT :=7369;
BEGIN
	SELECT ename,sal,hiredate INTO v_name,v_sal,v_hiredate FROM emp WHERE EMPNO=c_empno;--将查询字段结果赋值给变量用INTO关键字,前后顺序对应
	--计算纳税额
	v_tax_sal:=v_sal*c_tax_rate;
	--打印信息(使用声明处已被赋值的变量或常量)
	DBMS_OUTPUT.PUT_LINE(v_name||'的工资是'||v_sal||',雇佣日期是'||v_hiredate||',纳税额是'||v_tax_sal);
	--条件判断
	IF v_valid THEN
		DBMS_OUTPUT.PUT_LINE('已核实');
	END IF;
END;

四、PLSQL引用型变量和记录型变量

当一些变量在声明的时候就要求和表列具有完全一致的数据类型,因此可以直接使用原表列的类型用于定义变量。

1.引用型变量

是指其数据类型与已经定义的某个数据变量的类型相同,或者与数据库表的某个列的数据类型相同。如:v_name emp.ename%TYPE

DECLARE
	v_name emp.ename%TYPE;--v_name的数据类型和emp的ename字段相同
	v_sal emp.sal%TYPE;
BEGIN
	SELECT ename,sal INTO v_name,v_sal FROM emp WHERE empno=7788;
	DBMS_OUTPUT.PUT_LINE(v_name||'的工资是'||v_sal);
END;
2.记录型变量

变量定义的时候使用%ROWTYPE操作符,返回一整条记录的类型,其数据类型和数据库表的数据结构一致。如:emp_record emp%ROWTYPE是将emp表的一整条数据类型赋给变量emp_record,emp_record.ename:='ROSE’是取其一个字段ename形成子变量

DECLARE
	emp_record emp%ROWTYPE;--emp_record就是emp表的一条记录类型的集合
	c_tax_rate CONSTANT NUMBER(3,2)DEFAULT 0.02;
	v_tax_sal NUMBER(7,2);
BEGIN
	SELECT * INTO emp_record FROM EMP WHERE EMPNO=7788;
	v_tax_sal:=emp_record.sal*c_tax_rate;--emp_record.sal就是取其一个字段的子变量
	DBMS_OUTPUT.PUT_LINE(emp_record.ename||'的工资是'||emp_record.sal||',纳税额是'||v_tax_sal);--子变量直接使用emp表的字段名
END;

五、PLSQL运算符

1.关系运算符
运算符 含义
+ 加号
- 减号
* 乘号
** 乘方
DECLARE
	v_n1 NUMBER:=3;
	v_n2 NUMBER:=5;
BEGIN
	DBMS_OUTPUT.PUT_LINE(v_n1+v_n2);
	DBMS_OUTPUT.PUT_LINE(v_n1-v_n2);
	DBMS_OUTPUT.PUT_LINE(v_n1*v_n2);
	DBMS_OUTPUT.PUT_LINE(v_n1/v_n2);
	DBMS_OUTPUT.PUT_LINE(v_n1**v_n2);
END;
2.关系运算符
运算符 含义
= 等于
<>,!=,~=,^= 不等于
< 小于
> 大于
< 小于等于
> 大于等于
DECLARE
	v_n1 NUMBER(2):=&n1;--&替代变量,系统提示输入,navicat中无法使用
	v_n2 NUMBER(2):=&n2;
BEGIN
	IF (v_n1 = v_n2) THEN
		DBMS_OUTPUT.PUT_LINE('等于');
	ELSIF (v_n1 > v_n2) THEN
		DBMS_OUTPUT.PUT_LINE('大于');
	ELSIF (v_n1 < v_n2) THEN 
		DBMS_OUTPUT.PUT_LINE('小于');
	END IF;

	IF (v_n1 <> v_n2) THEN
		DBMS_OUTPUT.PUT_LINE('不等于');
	END IF;
END;
3.比较运算符
运算符 含义
IS NULL 是空值
BETWEEN… AND 介于两者之间
IN 等于列表中某个值
DECLARE
	v_num NUMBER :=3;
	v_str VARCHAR2(10):='apple';
BEGIN
	IF (v_num BETWEEN 0 AND 10) THEN
		DBMS_OUTPUT.PUT_LINE('位于0~10');
	ELSE
		DBMS_OUTPUT.PUT_LINE('不位于0~10');
	END IF;

	IF (v_num IN (1,3,5)) THEN
		DBMS_OUTPUT.PUT_LINE('在集合内');
	ELSE
		DBMS_OUTPUT.PUT_LINE('不在集合内');
	END IF;

	IF (v_num IS NULL) THEN
		DBMS_OUTPUT.PUT_LINE('为空');
	ELSE
		DBMS_OUTPUT.PUT_LINE('不为空');
	END IF;

	IF (v_str LIKE 'a%') THEN
		DBMS_OUTPUT.PUT_LINE('以a开头');
	ELSE
		DBMS_OUTPUT.PUT_LINE('不以a开头');
	END IF;
END;
4.逻辑运算符
运算符 含义
AND 逻辑与
OR 逻辑或
NOT 取反,如 IS NOT NULL, NOT IN
DECLARE
	v_b1 BOOLEAN :=TRUE;
	v_b2 BOOLEAN :=FALSE;
BEGIN
	IF (v_b1 AND v_b2) THEN
		DBMS_OUTPUT.PUT_LINE('AND--TRUE');
	END IF;
	IF (v_b1 OR v_b2) THEN
		DBMS_OUTPUT.PUT_LINE('OR--TRUE');
	END IF;
	IF (NOT v_b2) THEN
		DBMS_OUTPUT.PUT_LINE('n_b2--NOT--TRUE');
	END IF;
END;
5.NULL的运算特点
  • 空值加数字仍是空值:NULL+<数字>=NULL,所以如果要避免空值话,可以使用NVL函数
  • 空值连接字符,结束是字符:NULL||<字符串>=<字符串>
DECLARE
	v_num NUMBER :=3;
	v_str VARCHAR2(10):='apple';
BEGIN
		DBMS_OUTPUT.PUT_LINE(v_num+NULL);
		DBMS_OUTPUT.PUT_LINE(v_str||NULL);
END;

六、条件控制语句

1.IF 语句
  • 简单条件判断:IF-THEN
    语法格式:
IF condition THEN
	statements;
END IF;

示例:

--输入员工号,判断员工工资显示小于3000的员工
DECLARE
	v_name EMP.ENAME%TYPE;
	v_sal  EMP.SAL%TYPE;
BEGIN
	SELECT ename,sal INTO v_name,v_sal FROM EMP WHERE EMPNO=&n;
	IF v_sal<3000 THEN
	 DBMS_OUTPUT.PUT_LINE(v_name);
	END IF;
END;
  • 二重条件分支:IF-THEN-ELSE
    语法格式:
IF condition THEN
	statements;
ELSE
	statements;
END IF;

示例:

--输入员工号,判断员工工资,将工资小于3000的员工工资涨200,并显示涨工资的员工姓名,其它员工显示员工姓名及工资
DECLARE
	v_name EMPNEW.ENAME%TYPE;
	v_sal  EMPNEW.SAL%TYPE;
	v_empno EMPNEW.EMPNO%TYPE=7788;
BEGIN
	SELECT ename,sal INTO v_name,v_sal FROM EMPNEW WHERE EMPNO=v_empno;
	IF v_sal<3000 THEN
		UPDATE EMPNEW SET SAL=SAL+200 WHERE EMPNO=&v_empno;
		COMMIT;--数据库操作语言DML,执行后需要提交
		DBMS_OUTPUT.PUT_LINE(v_name||'涨工资了');
	ELSE
		DBMS_OUTPUT.PUT_LINE(v_name||'的工资是'||v_sal);
	END IF;
END;
  • 多重条件分支:IF-THEN-ELSIF
    语法格式:
IF condition THEN
	statements;
ELSIF condition THEN
	statements;	
ELSE
	statements;
END IF;

示例:

--输入员工号,判断员工工资,工资小于2000,显示低收入,工资小于6000,显示中等收入,其它显示高收入
DECLARE
	v_name EMPNEW.ENAME%TYPE;
	v_sal  EMPNEW.SAL%TYPE;
	v_empno EMPNEW.EMPNO%TYPE:=7788;
BEGIN
	SELECT ename,sal INTO v_name,v_sal FROM EMPNEW WHERE EMPNO=v_empno;
	IF v_sal<2000 THEN
		DBMS_OUTPUT.PUT_LINE(v_name||'低收入');
	ELSIF v_sal<6000 THEN
		DBMS_OUTPUT.PUT_LINE(v_name||'中等收入');
	ELSE
		DBMS_OUTPUT.PUT_LINE(v_name||'其它');		
	END IF;
END;
2.CASE

使用CASE语句执行多重条件分支操作,语句更加简洁执行效率更好。

  • 单一选择符进行等值比较
    语法格式:
CASE selector
	WHEN expression1 THEN sequence_of_statements1;
	WHEN expression2 THEN sequence_of_statements2;	
	...
	WHEN expressionN THEN sequence_of_statementsN;
	[ELSE sequence_of_statements;]
END CASE;

示例:

--输入成绩等级,判断属于哪个层次,并打印输出
DECLARE
	v_grade CHAR(1):='&n';
BEGIN
	CASE v_grade
		WHEN 'A' THEN
			DBMS_OUTPUT.PUT_LINE('优秀');
		WHEN  'B' THEN
			DBMS_OUTPUT.PUT_LINE('中等');
		ELSE
			DBMS_OUTPUT.PUT_LINE('其它');
	END CASE;
END;

  • 多种条件进行非等值比较
    语法格式:
CASE 
	WHEN condition1 THEN sequence_of_statements1;
	WHEN condition2 THEN sequence_of_statements2;	
	...
	WHEN conditionN THEN sequence_of_statementsN;
	[ELSE sequence_of_statements;]
END CASE;

示例:

--输入员工号,获取员工工资,判断工资,如果小于1500,补助加100,如果小于2500,补助加80,如果小于5000,补助加50
DECLARE
	v_name EMPNEW.ENAME%TYPE;
	v_sal  EMPNEW.SAL%TYPE;
	v_empno EMPNEW.EMPNO%TYPE:=7788;
BEGIN
	SELECT ename,sal INTO v_name,v_sal FROM EMPNEW WHERE EMPNO=v_empno;
	CASE
		WHEN v_sal<1500 THEN
			UPDATE EMPNEW SET COMM=NVL(COMM,0)+100 WHERE EMPNO=v_empno;
		WHEN v_sal<2500 THEN
			UPDATE EMPNEW SET COMM=NVL(COMM,0)+80 WHERE EMPNO=v_empno;
		WHEN v_sal<5000 THEN
			UPDATE EMPNEW SET COMM=NVL(COMM,0)+50 WHERE EMPNO=v_empno;
		COMMIT;
	END CASE;
END;

七、循环语句

1.基本循环

语法格式:

LOOP
	statement1;
	......
END LOOP;

示例:

--循环打印数字1~10
DECLARE
	v_n INT:=1;
BEGIN	
	LOOP
		DBMS_OUTPUT.PUT_LINE(v_n);
		v_n:=v_n+1;--变量自增
		EXIT WHEN v_n>10;--退出条件
	END LOOP;
END;
2.WHILE循环

语法格式:

WHILE condition LOOP
	statement1;
	......
END LOOP;

示例:

DECLARE
	v_n INT:=1;
BEGIN
	WHILE v_n <=10 LOOP
		DBMS_OUTPUT.PUT_LINE(v_n);
		v_n:=v_n+1;
	END LOOP;
END;
3.FOR循环

语法格式:

FOR counter in [REVERSE] lower_bound ...upper_bound LOOP
	statement1;
	......
END LOOP;

注意:步长默认为1,且不需要事先定义变量,REVERSE反相打印
示例:

BEGIN
	FOR i in 1..10 LOOP
		DBMS_OUTPUT.PUT_LINE(i);
	END LOOP;
END;

BEGIN
    FOR i  IN REVERSE 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE(i);
    END LOOP;
END;

八、嵌套循环和退出语句

1.嵌套循环

嵌套循环是指在一个循环语句中嵌入两一个循环语句,标号用于标记嵌套块或嵌套玄幻,使用<<label_name>>定义标号

DECLARE
	v_result INT;
BEGIN
	<<outter>>
	FOR i IN 1..5 LOOP
		<<inter>>
		FOR j IN 1..4 LOOP
			v_result:=i;
			EXIT outter WHEN i=3;
			DBMS_OUTPUT.PUT_LINE(i||j);
		END LOOP;
		DBMS_OUTPUT.PUT_LINE('内:'||v_result);--整个内循环结束一次记录一次i的值
	END LOOP;
	DBMS_OUTPUT.PUT_LINE('外:'||v_result);--当整个外循环全部结束后才会执行,此时就是结束外循环时j的值
END;
2.退出语句
  • EXIT和EXIT WHEN语句
    • EXIT语句用于直接退出当前循环
    • EXIT WHEN语句用于在满足特定条件时退出当前循环
DECLARE
	v_cnt INT:=1;
BEGIN
	LOOP
		DBMS_OUTPUT.PUT_LINE(v_cnt);
		EXIT WHEN v_cnt=10;
		v_cnt:=v_cnt+1;
	END LOOP;
END;
  • CONTINUE和CONTINUE WHEN语句
    • CONTINUE语句用于直接结束当前循环并继续下一组循环
    • CONTINUE WHEN语句用于在满足特定条件时结束当前循环并继续下一组循环
DECLARE
	v_cnt INT:=0;
BEGIN
	LOOP
		v_cnt:=v_cnt+1;
		CONTINUE WHEN v_cnt=5;
		DBMS_OUTPUT.PUT_LINE(v_cnt);
		EXIT WHEN v_cnt=10;
	END LOOP;
END;

九、顺序语句

1.GOTO语句

GOTO语句用于跳转到特定标号处执行语句
GOTO label_name;
注意当桑勇GOTO跳转到特定标号时,标号后面至少要包含一条执行语句
比较繁琐,减少使用

DECLARE
	v_cnt INT:=1;
BEGIN
	LOOP
		DBMS_OUTPUT.PUT_LINE(v_cnt);
		IF v_cnt=10 THEN
			--EXIT;
			GOTO end_loop;
		END IF;
		v_cnt:=v_cnt+1;
	END LOOP;
	<<end_loop>>
	DBMS_OUTPUT.PUT_LINE('循环结束');--标号后面至少一条语句
END;
2.NULL语句

NULL语句不会执行任何操作,并且会直接将控制传递到下一个语句,使用该语句的主要目的是提高PLSQL的可读性

--根据输入的员工号,判断员工的工资,如果工资小于3000,将该员工的不止加工资的2%,并打印输出某员工的奖金更新了
DECLARE
	v_name EMPNEW.ENAME%TYPE;
	v_sal  EMPNEW.SAL%TYPE;
	v_empno EMPNEW.EMPNO%TYPE:=7369;
BEGIN
	SELECT ename,sal INTO v_name,v_sal from EMPNEW WHERE empno=v_empno;
	IF v_sal<3000 THEN
		UPDATE EMPNEW set COMM=nvl(comm,0)+sal*0.2 WHERE ename=v_name;
		COMMIT;
		DBMS_OUTPUT.PUT_LINE(v_name||'的奖金更新了');
	ELSE
		NULL;--没有任何操作
	END IF;

END;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章