PL/SQL学习笔记

介绍

PL/SQL 编程语言是SQL 和 Oracle 关系数据库的过程扩展语言
是Oracle 编程环境中的一个工具

基本语法

S.No

Sections & Description

1

Declarations

此部分以关键字 DECLARE 开头。 它是一个可选部分,定义了程序中要使用的所有变量、游标、子程序和其他元素。

2

Executable Commands

此部分包含在关键字 BEGINEND 之间,它是必填部分。 它由程序的可执行 PL/SQL 语句组成。 它应该至少有一个可执行的代码行,可能只是一个NULL 命令,表示什么都不应该被执行。

3

Exception Handling

本节以关键字 EXCEPTION 开头。 此可选部分包含处理程序中的错误的异常

Declare (定义变量)

Begin (定义逻辑)

ExcepTion (异常处理)

End(流程结束)

每个 PL/SQL 语句都以分号 (;) 结束。 PL/SQL 块可以使用 BEGINEND 嵌套在其他 PL/SQL 块中。 以下是 PL/SQL 块的基本结构 −

DECLARE 
   <declarations section> 
BEGIN 
   <executable command(s)>
EXCEPTION 
   <exception handling> 
END;

标识符(java里的变量名,常量名等这一类名)

在PL/SQL中,标识符是用来命名变量、常量、游标、过程、函数、包、触发器、表类型、异常等程序元素的名称。它们是程序员为了识别和引用特定对象而自定义的名称。

举例说明:

  1. 变量(Variables)
    • 示例:声明一个名为 employee_name 的变量用于存储员工姓名。
Sql
1DECLARE
2    employee_name VARCHAR2(50);
3BEGIN
4    -- 一些操作...
5    employee_name := 'John Doe';
6END;
  1. 常量(Constants)
    • 示例:声明一个名为 MAX_EMPLOYEES 的常量表示公司最大员工数限制。
Sql
1DECLARE
2    MAX_EMPLOYEES CONSTANT NUMBER := 500;
3BEGIN
4    -- 使用常量进行逻辑判断
5    IF some_count <= MAX_EMPLOYEES THEN
6        -- 执行某些操作...
7    END IF;
8END;
  1. 游标(Cursors)
    • 示例:声明一个名为 emp_cursor 的游标来遍历员工表中的记录。
Sql
1DECLARE
2    CURSOR emp_cursor IS
3        SELECT * FROM employees WHERE department_id = 10;
4    v_employee_row employees%ROWTYPE;
5BEGIN
6    OPEN emp_cursor;
7    LOOP
8        FETCH emp_cursor INTO v_employee_row;
9        EXIT WHEN emp_cursor%NOTFOUND;
10        -- 处理每一行数据
11        DBMS_OUTPUT.PUT_LINE(v_employee_row.first_name || ' ' || v_employee_row.last_name);
12    END LOOP;
13    CLOSE emp_cursor;
14END;
  1. 过程(Procedures)
    • 示例:声明一个名为 update_salary 的过程,接受员工ID和新的薪水作为参数。
Sql
1CREATE OR REPLACE PROCEDURE update_salary (
2    p_employee_id IN employees.employee_id%TYPE,
3    p_new_salary  IN NUMBER
4) IS
5BEGIN
6    UPDATE employees SET salary = p_new_salary WHERE employee_id = p_employee_id;
7END update_salary;
  1. 函数(Functions)
    • 示例:声明一个名为 get_total_salary 的函数,返回指定部门所有员工的总薪水。
Sql
1CREATE OR REPLACE FUNCTION get_total_salary (
2    p_department_id IN departments.department_id%TYPE
3) RETURN NUMBER IS
4    total_salary NUMBER := 0;
5BEGIN
6    SELECT SUM(salary) INTO total_salary FROM employees WHERE department_id = p_department_id;
7    RETURN total_salary;
8END get_total_salary;

每个标识符必须遵循Oracle PL/SQL的命名规则:

  • 标识符的第一个字符必须是字母、下划线 (_) 或美元符号 ($)。
  • 其余字符可以是字母、数字、下划线或美元符号。
  • 标识符长度不能超过30个字符(在Oracle数据库12c及更高版本中,对于全局临时表空间中的对象,标识符长度可扩展至128个字符)。
  • 标识符默认不区分大小写,但在Oracle数据库中可以通过设置数据库的初始化参数来实现区分大小写(通常不建议这样做)。

PL/SQL各种符号(; = + - 等等)

分隔符

描述

+, -, *, /

加法、减法/否定、乘法、除法

%

属性指示符

'

字符串分隔符

.

组件选择器

(,)

表达式或列表分隔符

:

主变量指示符

,

项目分隔符

"

带引号的标识符分隔符

=

关系运算符

@

远程访问指示器

;

语句终止符

:=

赋值运算符

=>

关联运算符

||

连接运算符

**

指数运算符

<<, >>

标签分隔符(开始和结束)

/*, */

多行注释分隔符(开始和结束)

--

单行注释指示器

..

范围运算符

<, >, <=, >=

关系运算符

<>, '=, ~=, ^=

不等于的不同版本

PL/SQL 注释

单行注释:--

多行注释:/* */

数据类型(等价于java的int,string这个)

SCALAR(包含NUMBER、DATE 或 BOOLEAN等)

没有内部组件的单个值,例如 NUMBER、DATE 或 BOOLEAN。

Large Object (LOB)指向型数据类型

指向与其他数据项(例如文本、图形图像、视频剪辑和声音波形)分开存储的大型对象的指针。

标量数据类型

PL/SQL 提供了数据类型的子类型。 例如,数据类型 NUMBER 有一个称为 INTEGER 的子类型。 您可以在 PL/SQL 程序中使用子类型来使数据类型与其他程序中的数据类型兼容,同时将 PL/SQL 代码嵌入到另一个程序中,例如 Java 程序。

Numeric(对其执行算术运算的数值)

Character(表示单个字符或字符串的字母数字值。)

Boolean(对其执行逻辑操作的逻辑值。)

Datetime(日期和时间。)

PL/SQL 字符数据类型和子类型

以下是 PL/SQL 预定义字符数据类型及其子类型的详细信息 −

S.No

数据类型与描述

1

CHAR

最大长度为 32,767 字节的定长字符串

2

VARCHAR2

最大长度为 32,767 字节的可变长度字符串

3

RAW

最大大小为 32,767 字节的可变长度二进制或字节字符串,不由 PL/SQL 解释

4

NCHAR

最大长度为 32,767 字节的定长国家字符串

5

NVARCHAR2

最大长度为 32,767 字节的可变长度国家字符串

6

LONG

最大长度为 32,760 字节的可变长度字符串

7

LONG RAW

最大大小为 32,760 字节的可变长度二进制或字节字符串,不由 PL/SQL 解释

8

ROWID

物理行标识,普通表中的行地址

9

UROWID

通用行标识符(物理、逻辑或外部行标识符)

PL/SQL 数值数据类型和子类型

下表列出了 PL/SQL 预定义的数值数据类型及其子类型 −

S.No

数据类型与描述

1

PLS_INTEGER

-2,147,483,648 到 2,147,483,647 范围内的有符号整数,以 32 位表示

2

BINARY_INTEGER

-2,147,483,648 到 2,147,483,647 范围内的有符号整数,以 32 位表示

3

BINARY_FLOAT

单精度 IEEE 754 格式浮点数

4

BINARY_DOUBLE

双精度 IEEE 754 格式浮点数

5

NUMBER(prec, scale)

绝对值在 1E-130 到(但不包括)1.0E126 范围内的定点或浮点数。 一个 NUMBER 变量也可以表示 0

6

DEC(prec, scale)

ANSI 特定定点类型,最大精度为 38 位十进制数字

7

DECIMAL(prec, scale)

IBM 特定定点类型,最大精度为 38 位十进制数字

8

NUMERIC(pre, secale)

浮点型,最大精度为 38 位十进制数字

9

DOUBLE PRECISION

ANSI 特定浮点类型,最大精度为 126 位二进制位(约 38 位十进制位)

10

FLOAT

ANSI 和 IBM 特定的浮点类型,最大精度为 126 位二进制位(大约 38 位十进制位)

11

INT

ANSI 特定整数类型,最大精度为 38 位十进制数字

12

INTEGER

ANSI 和 IBM 特定整数类型,最大精度为 38 位十进制数字

13

SMALLINT

ANSI 和 IBM 特定整数类型,最大精度为 38 位十进制数字

14

REAL

浮点型,最大精度为 63 位二进制(约 18 位十进制)

PL/SQL 布尔数据类型

BOOLEAN 数据类型存储用于逻辑运算的逻辑值。 逻辑值是布尔值 TRUEFALSE 以及值 NULL

但是,SQL 没有与 BOOLEAN 等效的数据类型。 因此,布尔值不能用于 −

  • SQL 语句
  • 内置 SQL 函数(如 TO_CHAR
  • 从 SQL 语句调用的 PL/SQL 函数

PL/SQL 日期时间和间隔类型

DATE 数据类型用于存储固定长度的日期时间,其中包括自午夜以来的时间(以秒为单位)。 有效日期范围从公元前 4712 年 1 月 1 日到公元 9999 年 12 月 31 日。

默认日期格式由 Oracle 初始化参数 NLS_DATE_FORMAT 设置。 例如,默认值可能是"DD-MON-YY",其中包括一个两位数的月份日期、月份名称的缩写和年份的最后两位数。 例如,01-OCT-12。

每个 DATE 包括世纪、年、月、日、小时、分钟和秒。 下表显示了每个字段的有效值 −

字段名称

有效日期时间值

有效区间值

YEAR

-4712 到 9999(不包括第 0 年)

任意非零整数

MONTH

01 to 12

0 to 11

DAY

01 到 31(受 MONTH 和 YEAR 的值限制,根据 locale 的日历规则)

任意非零整数

HOUR

00 到 23

0 到 23

MINUTE

00 到 59

0 到 59

SECOND

00 到 59.9(n),其中 9(n) 是时间小数秒的精度

0 到 59.9(n),其中 9(n) 是间隔小数秒的精度

PL/SQL 大对象 (LOB) 数据类型

大型对象 (LOB) 数据类型是指大型数据项,例如文本、图形图像、视频剪辑和声音波形。 LOB 数据类型允许对这些数据进行高效、随机、分段的访问。 以下是预定义的 PL/SQL LOB 数据类型 −

数据类型

描述

大小

BFILE

用于将大型二进制对象存储在数据库外的操作系统文件中。

取决于系统。 不能超过 4 GB。

BLOB

用于在数据库中存储大型二进制对象。

8 到 128 太字节 (TB)

CLOB

用于在数据库中存储大块字符数据。

8 到 128 TB

NCLOB

用于在数据库中存储大块 NCHAR 数据。

8 到 128 TB

PL/SQL 中的 NULL 空值

PL/SQL NULL 值表示缺失未知数据,它们不是整数、字符或任何其他特定数据类型。 请注意,NULL 与空数据字符串或空字符值 '\0' 不同。 可以分配一个空值,但它不能等同于任何东西,包括它自己。

使用示例

DECLARE 
   num1 INTEGER; 
   num2 REAL; 
   num3 DOUBLE PRECISION; 
BEGIN 
   null; 
END; 
/ 

变量(类似于实现类定义的一个个String name = "zhangsan";)

变量是我们的程序可以操作的存储区域的名称。 PL/SQL 中的每个变量都有特定的数据类型,它决定了变量内存的大小和布局

变量声明的语法

个数
variable_name [CONSTANT] datatype [NOT NULL] [:= | DEFAULT initial_value] 

人话:(备注:也可给变量类型添加大小)
1:变量名称   变量类型 := 变量值
2:变量名称   变量类型 default 变量值
2:变量名称   变量类型 not null default 变量值    (添加约束变量)
3:变量名称   变量类型;     (初始化后为null)


示例:
declare
    message varchar2(20) := 'hello word!';
    message varchar2(20) default 'hello word!';
    message varchar2(20) not null := 'hello word!';
    message varchar2(20);
begin
    DBMS_OUTPUT.PUT_LINE(message);
END;
DECLARE 
   a integer := 10; 
   b integer := 20; 
   c integer; 
   f real; 
BEGIN 
   c := a + b; 
   dbms_output.put_line('Value of c: ' || c); 
   f := 70.0/3.0; 
   dbms_output.put_line('Value of f: ' || f); 
END; 
/  

打印:
Value of c: 30 
Value of f: 23.333333333333333333  

PL/SQL procedure successfully completed. 

变量的作用域(等价于JAVA的作用域)

PL/SQL 允许嵌套块,即每个程序块可以包含另一个内部块。 如果变量在内部块中声明,则外部块无法访问它。

  • Local 局部变量 − 在内部块中声明且外部块无法访问的变量。
  • Global 全局变量 − 在最外层块或包中声明的变量。
declare
    -- 全局变量
    message1 varchar2(20)          := 'hello word!';
    message2 varchar2(20) default 'hello word!';
    message3 varchar2(20) not null := 'hello word!';
    message4 varchar2(20);
begin
    --      DBMS_OUTPUT.PUT_LINE(message1 || message5); 这里没法成功,因为message5是局部变量
    -- 局部变量
    declare
        message5 varchar2(20);
    begin
        DBMS_OUTPUT.PUT_LINE(message1 || message5);
    end;
END;

%TYPE 引用型变量(引用表字段数据类型,随表字段变化而变化)

%TYPE 关键字用于声明一个变量,并让其数据类型与数据库中的某个列相同。这样做的好处是,如果表结构发生变化(例如,列的数据类型改变),相关的变量也会自动适应新的数据类型,无需手动修改代码。
DECLARE
    -- 声明一个名为 emp_salary 的变量,其数据类型与 employees 表的 salary 列相同
    emp_salary employees.salary%TYPE;
    
    v_employee_id employees.employee_id%TYPE := 100; -- 假设我们有一个已知的员工ID
BEGIN
    SELECT salary INTO emp_salary FROM employees WHERE employee_id = v_employee_id;
    DBMS_OUTPUT.PUT_LINE('Employee Salary: ' || emp_salary);
END;

%ROWTYPE 记录型变量(引用表 一行的 数据)

%ROWTYPE 关键字用于声明一个记录类型变量,该变量包含了对应表中一行的所有列及其相应的数据类型。它可以用来一次性处理表中的整行数据。
DECLARE
    -- 声明一个名为 emp_record 的变量,其数据类型与 employees 表的一行记录完全一致
    emp_record employees%ROWTYPE;
BEGIN
    -- 通过主键查询员工记录并填充到记录型变量中
    SELECT * INTO emp_record FROM employees WHERE employee_id = 100;

    -- 输出员工的姓名和薪水
    DBMS_OUTPUT.PUT_LINE('Employee Name: ' || emp_record.first_name || ' ' || emp_record.last_name);
    DBMS_OUTPUT.PUT_LINE('Employee Salary: ' || emp_record.salary);
END;

INTO(表数据赋值给变量)

SELECT INTO 语句为 PL/SQL 变量赋值。 对于SELECT 列表 中的每一项,INTO 列表 中必须有一个对应的、类型兼容的变量。

DECLARE 
   c_id customers.id%type := 1; 
   c_name  customers.name%type; 
   c_addr customers.address%type; 
   c_sal  customers.salary%type; 
BEGIN 
   SELECT name, address, salary INTO c_name, c_addr, c_sal 
   FROM customers 
   WHERE id = c_id;  
   dbms_output.put_line 
   ('Customer ' ||c_name || ' from ' || c_addr || ' earns ' || c_sal); 
END; 
/

常量(一旦定义,不可改变)

语法

常量名  CONSTANT(常量关键字) 常量类型 := 常量值;

PI CONSTANT NUMBER := 3.141592654; 
DECLARE
2    -- 声明一个名为MAX_EMPLOYEES的常量,表示公司最大员工数限制
3    MAX_EMPLOYEES CONSTANT NUMBER := 500;
4
5    -- 声明一个名为PI的常量,用于存储圆周率
6    PI CONSTANT NUMBER := 3.14159265358979323846;
7
8BEGIN
9    -- 使用常量进行逻辑判断和计算
10    IF (SELECT COUNT(*) FROM employees) > MAX_EMPLOYEES THEN
11        DBMS_OUTPUT.PUT_LINE('公司员工数量超过最大限制:' || MAX_EMPLOYEES);
12    END IF;
13
14    -- 计算半径为1米的圆的面积
15    DECLARE
16        radius CONSTANT NUMBER := 1; -- 半径也为常量
17        circle_area NUMBER;
18    BEGIN
19        circle_area := PI * POWER(radius, 2);
20        DBMS_OUTPUT.PUT_LINE('半径为1米的圆面积是: ' || circle_area || ' 平方米');
21    END;
22END;

在字符串文字中嵌入单引号,请将两个单引号并排放置

DECLARE 
   message  varchar2(30):= 'That''s tutorialspoint.com!'; 
BEGIN 
   dbms_output.put_line(message); 
END; 
/  
That's tutorialspoint.com!  

条件判断语句

if then end if (单选)

IF (a <= 20 这个是条件表达式)
THEN c:= c+1;  如果为真执行Then后面的代码
END IF;  结束if判断

if then else end if (双选)

declare
   a number(2):=1;
Begin
    if a=1
        then a:= a+1;
        else a:= a+2;  上一个不成立,就走这给一个。经我测试,好像只能写一个else
        end if;
end;

if elsif then ...(多个elsif then) end if (多选)

declare
   a number(2):=1;
Begin
    if a=1 then a:= a+1;
    elsif (a= 2) then a:= a+2;
    elsif a= 3 then a:= a+3;
    elsif a= 4 then a:= a+4;
    end if;
end;

CASE 语句(等价IF,但是可以SQL语句用)

CASE selector 
   WHEN 'value1' THEN S1; 
   WHEN 'value2' THEN S2; 
   WHEN 'value3' THEN S3; 
   ... 
   ELSE Sn;  -- default case 
END CASE;
DECLARE 
   grade char(1) := 'B'; 
BEGIN 
   case  
      when grade = 'A' then dbms_output.put_line('Excellent'); 
      when grade = 'B' then dbms_output.put_line('Very good'); 
      when grade = 'C' then dbms_output.put_line('Well done'); 
      when grade = 'D' then dbms_output.put_line('You passed'); 
      when grade = 'F' then dbms_output.put_line('Better try again'); 
      else dbms_output.put_line('No such grade'); 
   end case; 
END; 
/

IF嵌套

DECLARE 
   a number(3) := 100; 
   b number(3) := 200; 
BEGIN 
   -- 检查布尔条件
   IF( a = 100 ) THEN 
   -- 如果条件为真,则检查以下内容
      IF( b = 200 ) THEN 
      -- 如果条件为真,则打印以下内容
      dbms_output.put_line('Value of a is 100 and b is 200' ); 
      END IF; 
   END IF; 
   dbms_output.put_line('Exact value of a is : ' || a ); 
   dbms_output.put_line('Exact value of b is : ' || b ); 
END; 
/ 

循环

Loop(java for循环)

loop 
  逻辑
exit when 终止循环条件
end loop;
declare
    x number(10) := 10;
begin
    Loop  (循环的固定格式)
        dbms_output.put_line(x); 
        x := x + 10;
        exit when x > 50; (exit when代表,如果x>50,则循环结束.每次+10,所以60结束循环)
    end loop;  (循环的固定格式)
    dbms_output.put_line('最后输出这句: x=' || x);   (这里最后输出:最后输出这句=60)
end ;
DECLARE 
   x number := 10; 
BEGIN 
   LOOP 
      dbms_output.put_line(x); 
      x := x + 10; 
      IF x > 50 THEN 
         exit; 
      END IF; 
   END LOOP; 
   -- after exit, control resumes here  
   dbms_output.put_line('After Exit x is: ' || x); 
END; 
/

WHILE (跟 java for循环 没区别)

备注:他这里不是输出刚好大于循环条件的值,而是输出最后一个符合循环条件的值。

如:条件a < 20,则a最后输出为19

while 终止循环条件 loop
  逻辑代码
end loop;
DECLARE 
   a number(2) := 10; 
BEGIN 
   WHILE a < 20 LOOP 
      dbms_output.put_line('value of a: ' || a); 
      a := a + 1; 
   END LOOP; 
END; 
/ 

备注:他这里最终会输出19.
      而不是20.如果是java先判断是19<20,然后打印语句,再接着执行19+1,然后while不成立,
      输出20.但这个pl/sql输出的是19

For(范围循环)

格式:
for  变量名  in  起始值 .. 结束值 loop

end loop 结束循环
DECLARE 
   a number(2); 
BEGIN 
   FOR a in 1 .. 3 LOOP 
      dbms_output.put_line('value of a: ' || a); 
  END LOOP; 
END; 
/

输出:value of a:1   value of a:2    value of a:3

reverse(For循环 加此 关键字 倒叙输出)

DECLARE 
   a number(2) ; 
BEGIN 
   FOR a IN REVERSE 1 .. 3 LOOP 
      dbms_output.put_line('value of a: ' || a); 
   END LOOP; 
END; 
/

输出:value of a:3   value of a:2    value of a:1

循环 关键字 解释

exit (立即结束当前循环)

Exit 语句完成循环并将控制传递给紧接在 END LOOP 之后的语句。

1:当在循环中遇到 EXIT 语句时,循环立即终止
2:嵌套循环,EXIT 语句将停止执行最内层循环并开始执行该块之后的下一行代码。
DECLARE 
   a number(2) := 10; 
BEGIN 
   -- while loop execution  
   WHILE a < 20 LOOP 
      dbms_output.put_line ('value of a: ' || a); 
      a := a + 1; 
      IF a > 15 THEN 
         -- terminate the loop using the exit statement 
         EXIT; 
      END IF; 
   END LOOP; 
END; 
/ 

value of a: 10 
value of a: 11 
value of a: 12 
value of a: 13 
value of a: 14 
value of a: 15  

exit when (立即结束当前循环)

Exit 语句完成循环并将控制传递给紧接在 END LOOP 之后的语句。

EXIT-WHEN 语句允许评估 WHEN 子句中的条件。 如果条件为真,则循环完成,控制权立即传递到 END LOOP 之后的语句。
DECLARE 
   a number(2) := 10; 
BEGIN 
   -- while loop execution  
   WHILE a < 20 LOOP 
      dbms_output.put_line ('value of a: ' || a);  
      a := a + 1; 
      -- terminate the loop using the exit when statement 
   EXIT WHEN a > 15; 
   END LOOP; 
END;   
/

value of a: 10 
value of a: 11 
value of a: 12 
value of a: 13 
value of a: 14 
value of a: 15  

continue(跳过当前,执行下一轮)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值