PL/SQL基础
词法单元
分隔符(Delimiters)
分隔符用于标记词法元素之间的分割,可以是一个字符,也可以是由多个字符组合组成的,都有特殊的意义,例如“+”。
Delimiter | Meaning |
---|---|
+ | Addition operator |
:= | Assignment operator |
% | Attribute indicator |
' | Character string delimiter |
. | Component indicator |
|| | Concatenation operator |
/ | Division operator |
( | Expression or list delimiter (begin) |
) | Expression or list delimiter (end) |
, | Item separator |
<< | Label delimiter (begin) |
>> | Label delimiter (end) |
/* | Multiline comment delimiter (begin) |
*/ | Multiline comment delimiter (end) |
* | Multiplication operator |
" | Quoted identifier delimiter |
.. | Range operator |
= | Relational operator (equal) |
<> | Relational operator (not equal) |
!= | Relational operator (not equal) |
~= | Relational operator (not equal) |
^= | Relational operator (not equal) |
< | Relational operator (less than) |
> | Relational operator (greater than) |
<= | Relational operator (less than or equal) |
>= | Relational operator (greater than or equal) |
-- | Single-line comment indicator |
; | Statement terminator |
- | Subtraction or negation operator |
标识符(Identifiers)
标识符用于命名PL/SQL语法单元,包括:
- 常量
- 变量
- 异常
- 游标
- 关键字
- 标签
- 保留字
- 类型
标识符中的每个字符都是有意义的,例如lastname和last_name是不同的。必须通过一个或多个空白或者一个标点符号来分隔相邻的标识符。标识符的大小写是不敏感的。例如lastname、Lastname、LASTNAME是相同的。
保留字和关键字
PL/SQL中有一些具有特殊意义的标识符,被称作保留字和关键字。不能使用保留字做为用户定义的标识符。可以用关键字作为用户定义的标识符。
用户自定义保留字
PL/SQL标识符的长度限制,请参照GBase 8s语法。
用户标识符:
- 以字符开头
- 可以包含字母、数字和$, ,_字符
- 不能为保留字
例如以下是可接受的标识符:
X
t2
credit_limit
LastName
oracle$number
money$$$tree
try_again_
PL/SQL不容许在标识符中使用分隔符,如下所示:
mine&yours -- ampersand (&) is not allowed
debit-amount -- hyphen (-) is not allowed
on/off -- slash (/) is not allowed
user id -- space is not allowed
PL/SQL对标识符不区分大小写,PL/SQL认为下面命名是相同的。例子
lastname
LastName
LASTNAME
每个字符都是有意义的。例如,PL/SQL考虑以下是不同的。例子。
lastname
last_name
为了让PL/SQL程序更加易读,取名要有意义。例如
cost_per_thousand --- 易懂
cpt --- 难懂
★自定义名称
- 作用域
同一作用域内声明的标识符必须是唯一的。即使是数据类型不同,变量名或参数名也不能相同。
例如:
valid_id BOOLEAN ;
valid_id VARCHAR2(5); -- not allowed duplicate identifier
- 大小写敏感
与所有标识符一样,常量、变量和参数的名称是大小写不敏感的
zip_code INTEGER ;
ZIP_CODE INTEGER ; -- same as zip_code
- 名称解析
在有二义性的SQL语句中,数据库列的名称优先于局部变量和形参。
例如,如果在WHERE子句中使用使用名字相同的变量和列,SQL将这两个名称都视为具有相同名称的列。下面的DELETE语句会从EMP表中删除所有雇员的信息。而不是只删除KING的雇员。
CREATE PROCEDURE p_1_4_3_1 AS
ename VARCHAR2(10) := 'KING';
BEGIN
DELETE FROM emp
WHERE ename = ename;
END;
/
★标识符范围和可见性
对标识符的引用可以通过作用域和可见度来进行解析。
- 作用域:引用标识符的程序单元区域。
- 可见度:一个标识符只有在它的作用域内才能可见。可以在作用域内不使用限定词而直接引用。
声明的标识符对于所在块就是本地的,对于子块就是全局的。如果全局标识符在子块中重新定义,那么两个变量在子块的作用域都是存在的,但只有本地标识符是可见的,如果这时候想引用全局标识符,就要加限定符。虽然不能再同一块中两次声明同一标识符,但可以在不同的块中声明同一标识符。这两个标识符是相互独立的,互不影响。但一个块中不能引用另一同级别块中的变量。因为对它而言,同级块中的标识符既不是本地也不是全局的。如下图:
如下示例展示了几个标识符的范围和可见性。第一个子块重新声明全局标识符a。为了引用全局变量a,第一个子块必须使用外部块的名称来限定它,但是外部块没有名称。因此,第一个子块不能引用全局变量a;它只能引用其局部变量a,因为子块在同一层,第一个子块不能引用d,第二个子块不能引用c。
--Outer block:
CREATE PROCEDURE p_1_5 AS
a CHAR; -- Scope of a (CHAR) begins
b REAL; -- Scope of b begins
BEGIN
-- Visible: a (CHAR), b
-- First sub-block:
DECLARE
a INTEGER; -- Scope of a (INTEGER) begins
c REAL; -- Scope of c begins
BEGIN
-- Visible: a (INTEGER), b, c
NULL;
END; -- Scopes of a (INTEGER) and c end
-- Second sub-block:
DECLARE
d REAL; -- Scope of d begins
BEGIN
-- Visible: a (CHAR), b, d
NULL;
END; -- Scope of d ends
-- Visible: a (CHAR), b
END; -- Scopes of a (CHAR) and b end
/
★相同范围内的重复标识符
您不能在同一个PL/SQL单元中两次声明相同的标识符。如果您这样做,当您引用重复标识符时,会出现错误,如本例所示。
CREATE PROCEDURE p_1_5_3_1 AS
id BOOLEAN;
id VARCHAR2(5); -- duplicate identifier
BEGIN
id := FALSE;
END;
/
669: Variable(id) redeclared.
Error in line 3
Near character position 2
注释(Comments)
PL/SQL编译器忽略注释。向程序添加注释可以增强可读性。通常,使用注释来描述每个代码段的用途,也可以将代码通过注释禁用。
★单行注释
--,一直到行为结束,例子如下所示:
--select 1 from dual;
★多行注释
/*注释内容*/,例子如下所示:
/* select 1 from dual;
select 2 from dual;*/
常量变量
PL/SQL程序将值存储在变量和常量中。当程序执行时变量的值可以更改,但常量的值不能更改。声明为值分配存储空间,指定其数据类型,并命名存储位置,以便后续可以引用它。
声明
★声明变量
变量声明需要指定变量名称和数据类型。对于大多数据类型,声明变量也可以指定初始值。变量名称必须是有效的用户定义标识符。数据类型可以是任何PL/SQL数据类型。数据类型可以是简单地(SCALAR),也可以是复合的。赋值运算符后面的表达式可以任意复杂,并且可以引用以前初始化的变量。每次执行程序时,都会初始化变量。
例如:
CREATE PROCEDURE p_1_2_1_1 AS
birthday DATE;
emp_count SMALLINT := 0;
pi REAL := 3.14159;
radius REAL := 1;
area REAL := pi * radius*2;
BEGIN
NULL;
END;
/
★声明常量
声明常量时,需要将关键字CONSTANT放在类型说明符之前。
常量必须在其声明中初始化。这个下面的例子声明命名了实数类型的常量,并指定了一个不可更改的值5000给常数。
CREATE PROCEDURE p_1_2_2_1 AS
credit_limit CONSTANT REAL := 5000.00;
max_days_in_year CONSTANT INTEGER := 366;
urban_legend CONSTANT BOOLEAN := FALSE;
BEGIN
NULL;
END;
/
不允许向前引用
下面的声明是不合法的
maxi INTEGER := 2 * mini; -- not allowed
mini INTEGER := 15;
下面的声明也是不允许的
j, k SMALLINT ; -- not allowed
赋值
有3中方式赋值:
- 使用赋值语句将表达式赋值给变量
- 使用SELECT INTO 或 FETCH语句赋值给变量
- 将变量传递给子程序的OUT或IN OUT 参数在子程序里赋值。
声明变量时,可以将默认值赋给该变量或声明后使用赋值语句。赋值运算符(:=)后面的表达式可以任意复杂。默认情况下,变量初始化为空。除非显式初始化变量,否则其值为未知的。
★用赋值语句给变量赋值
这个例子声明了几个变量(为一些变量指定初始值),然后使用赋值语句将表达式的值赋给它们。
CREATE PROCEDURE p_1_6_1 AS -- You can assign initial values here
wages NUMBER;
hours_worked NUMBER := 40;
hourly_salary NUMBER := 22.50;
bonus NUMBER := 150;
country VARCHAR2(128);
counter NUMBER := 0;
done BOOLEAN;
valid_id BOOLEAN;
emp_rec1 employees%ROWTYPE;
emp_rec2 employees%ROWTYPE;
TYPE commissions IS TABLE OF NUMBER INDEX BY PLS_INTEGER;
comm_tab commissions;
BEGIN -- You can assign values here too
wages := (hours_worked * hourly_salary) + bonus;
country := 'France';
country := UPPER('Canada');
done := (counter > 100);
valid_id := TRUE;
emp_rec1.first_name := 'Antonio';
emp_rec1.last_name := 'Ortiz';
emp_rec1 := emp_rec2;
comm_tab(5) := 20000 * 0.15;
END;
/
★用SELECT INTO语句给变量赋值
本例使用SELECT INTO语句将employee_id为100的雇员的工资的10%赋值给变量 bonus。
CREATE PROCEDURE p_1_6_2 AS
bonus NUMBER(8,2);
BEGIN
SELECT salary * 0.10 INTO bonus
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE('bonus = ' || TO_CHAR(bonus));
END;
/
--Result:
--bonus = 2400
★IN OUT子程序参数给变量赋值
这个示例将变量new_sal传递给过程adjust_salary。该过程将一个值赋给相应的形式参数sal。由于sal是一个 IN OUT 参数,变量new_sal在过程结束后保留了赋值。
CREATE PROCEDURE adjust_salary (
emp NUMBER,
sal IN OUT NUMBER,
adjustment NUMBER
) IS
BEGIN
sal := sal + adjustment;
END;
/
CREATE PROCEDURE p_1_6_3 AS
emp_salary NUMBER(8,2);
BEGIN
SELECT salary INTO emp_salary
FROM employees
WHERE employee_id = 100;
DBMS_OUTPUT.PUT_LINE
('Before invoking procedure, emp_salary: ' || emp_salary);
adjust_salary (100, emp_salary, 1000);
DBMS_OUTPUT.PUT_LINE
('After invoking procedure, emp_salary: ' || emp_salary);
END;
/
--Result:
--Before invoking procedure, emp_salary: 24000
--After invoking procedure, emp_salary: 25000
★给BOOLEAN变量赋值
只有值TRUE、FALSE和NULL可以分配给布尔变量。这个示例布尔变量done默认初始化为NULL,后将其赋值为FALSE。
CREATE PROCEDURE p_1_6_4 AS
done BOOLEAN; -- Initial value is NULL by default
counter NUMBER := 0;
BEGIN
done := FALSE; -- Assign literal value
WHILE done != TRUE -- Compare to literal value
LOOP
counter := counter + 1;
done := (counter > 500); -- Assign value of BOOLEAN expression
END LOOP;
END;
/
初始化
在变量的声明中初始化时可选的。除非指定NO NULL。在常量中初始化时必须的。常量不指定初始值,默认就为NULL。使用:=和DEFAULT关键字进行初始化。后边跟表达式,表达式可以包含前面已经声明的常量或已经初始化的变量。
CREATE PROCEDURE p_1_2_3_1 AS
hours_worked INTEGER := 40;
employee_count INTEGER := 0;
pi CONSTANT REAL := 3.14159;
radius REAL := 1;
area REAL := (pi * radius*2);
BEGIN
NULL;
END;
/
CREATE PROCEDURE p_1_2_3_2 AS
counter INTEGER; -- initial value is NULL by default
BEGIN
counter := counter + 1; -- NULL + 1 is still NULL
IF counter IS NULL THEN
DBMS_OUTPUT.PUT_LINE('counter is NULL.');
END IF;
END;
/
--Result
--counter is NULL
CREATE PROCEDURE p_1_2_3_3 AS
blood_type CHAR DEFAULT 'O'; -- Same as blood_type CHAR := 'O';
hours_worked INTEGER DEFAULT 40; -- Typical value
employee_count INTEGER := 0; -- No typical value
BEGIN
NULL;
END;
/
表达式
一个表达式始终返回唯一值。表达式有:
- 单个常量或变量
- 一个操作符和单个操作数
- 二元操作符和2个操作数
操作数可以是:常量、变量、文字等。操作数的数据类型决定了表达式的数据类型。
连接运算符
CREATE PROCEDURE p_1_7_1_1 AS
x VARCHAR2(4) := 'suit';
y VARCHAR2(4) := 'case';
BEGIN
DBMS_OUTPUT.PUT_LINE (x || y);
END;
/
--Result:
--suitcase
操作优先级
运算是一元操作符操作及单个操作数或二元操作符及其两个操作数。表达式中的操作按照操作符的优先级的顺序计算。表达式中的操作按优先顺序计算。显示从最高到最低的运算符优先级。具有同等优先级的运算符。
Operator | Operation |
---|---|
+, - | identity, negation |
*, / | multiplication, division |
+, -, || | addition, subtraction,concatenation |
=, <, >, <=, >=, <>, !=, ~=, ^=, IS NULL, LIKE, BETWEEN, IN | comparison |
NOT | negation |
AND | conjunction |
OR | inclusion |
★用括号控制评价顺序
CREATE PROCEDURE p_1_7_2_1 AS
a INTEGER := 1+2*2;
b INTEGER := (1+2)*2;
BEGIN
DBMS_OUTPUT.PUT_LINE('a = ' || TO_CHAR(a));
DBMS_OUTPUT.PUT_LINE('b = ' || TO_CHAR(b));
END;
/
--Result:
--a = 5
--b = 6
★嵌套括号的表达式
在本例中,首先计算操作(1+2)和(3+4),分别生成值3和7。接下来,对操作3*7进行评估,生成结果21。最后,计算操作21/7,生成最终值3。
CREATE PROCEDURE p_1_7_2_2 AS
a INTEGER := ((1+2)*(3+4))/7;
BEGIN
DBMS_OUTPUT.PUT_LINE('a = ' || TO_CHAR(a));
END;
/
--Result:
--a = 3
★运算符的优先级
这个例子展示了运算符优先级和括号在几个更复杂的表达式中的效果。
CREATE PROCEDURE p_1_7_2_3 AS
salary NUMBER := 60000;
commission NUMBER := 0.10;
BEGIN
-- Division has higher precedence than addition:
DBMS_OUTPUT.PUT_LINE('5 + 12 / 4 = ' || TO_CHAR(5 + 12 / 4));
DBMS_OUTPUT.PUT_LINE('12 / 4 + 5 = ' || TO_CHAR(12 / 4 + 5));
-- Parentheses override default operator precedence:
DBMS_OUTPUT.PUT_LINE('8 + 6 / 2 = ' || TO_CHAR(8 + 6 / 2));
DBMS_OUTPUT.PUT_LINE('(8 + 6) / 2 = ' || TO_CHAR((8 + 6) / 2));
-- Most deeply nested operation is evaluated first:
DBMS_OUTPUT.PUT_LINE('100 + (20 / 5 + (7 - 3)) = ' || TO_CHAR(100 + (20 / 5 + (7 - 3))));
-- Parentheses, even when unnecessary, improve readability:
DBMS_OUTPUT.PUT_LINE('(salary * 0.05) + (commission * 0.25) =
' || TO_CHAR((salary * 0.05) + (commission * 0.25)));
DBMS_OUTPUT.PUT_LINE('salary * 0.05 + commission * 0.25 =
' || TO_CHAR(salary * 0.05 + commission * 0.25));
END;
/
--Result:
--5 + 12 / 4 = 8
--12 / 4 + 5 = 8
--8 + 6 / 2 = 11
--(8 + 6) / 2 = 7
--100 + (20 / 5 + (7 - 3)) = 108
--(salary * 0.05) + (commission * 0.25) = 3000.025
--salary * 0.05 + commission * 0.25 = 3000.025
逻辑运算符
逻辑运算符AND、OR和NOT遵循下表所示的三态逻辑。但是要避免使用NULL的异常情况。
AND和OR是二进制运算符;NOT是一元运算符。当且仅当两个操作数为TURE,AND返回TURE;当有一个为TURE,OR返回TURE;NOT返回操作数的相反值. NOT NULL还是NULL。因为NULL本身就是一个不确定的值。
★程序输出布尔变量
这个例子创建一个print_boolean程序,它输出一个 BOOLEAN 变量的值。该过程使用“IS [NOT] NULL Operator”。
CREATE OR REPLACE PROCEDURE print_boolean (
b_name VARCHAR2, b_value BOOLEAN) AUTHID DEFINER IS
BEGIN
IF b_value IS NULL THEN
DBMS_OUTPUT.PUT_LINE (b_name || ' = NULL');
ELSIF b_value = TRUE THEN
DBMS_OUTPUT.PUT_LINE (b_name || ' = TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE (b_name || ' = FALSE');
END IF;
END;
/
★与操作
如果两个操作数都为真,则返回TRUE。
x | y | x AND y | x OR y | NOT x |
---|---|---|---|---|
TRUE | TRUE | TRUE | TRUE | FALSE |
TRUE | FALSE | FALSE | TRUE | FALSE |
TRUE | NULL | NULL | TRUE | FALSE |
FALSE | TRUE | FALSE | TRUE | TRUE |
FALSE | FALSE | FALSE | FALSE | TRUE |
FALSE | NULL | FALSE | NULL | TRUE |
NULL | TRUE | NULL | TRUE | NULL |
NULL | FALSE | FALSE | NULL | NULL |
NULL | NULL | NULL | NULL | NULL |
CREATE OR REPLACE PROCEDURE p_1_7_3_2
AS
x boolean :=true;
y boolean :=false;
BEGIN
if x and y then
DBMS_OUTPUT.PUT_LINE('true');
else
DBMS_OUTPUT.PUT_LINE('x and y');
end if;
END;
/
--Result:
-- x and y
★或运算
或返回TRUE,如果操作数是正确的。
CREATE OR REPLACE PROCEDURE p_1_7_3_3
AS
x boolean :=true;
y boolean :=false;
BEGIN
if x or y then
DBMS_OUTPUT.PUT_LINE('x or y');
end if;
END;
/
--Result:
-- x or y
★求反算符
NOT 返回其操作数的相反值,除非操作数为 NULL。NOT NULL返回NULL,因为NULL是一个不确定值。
CREATE OR REPLACE PROCEDURE p_1_7_3_4
AS
x boolean :=true;
BEGIN
if not x then
DBMS_OUTPUT.PUT_LINE('true');
else
DBMS_OUTPUT.PUT_LINE('not x');
end if;
END;
/
--Result:
--not x
★不**相等比较中的NULL值**
在本例中,您可能期望运行的语句序列,因为x和y看起来不相等。但是,空值是不确定的,不论x = y是否未知。因此, IF条件为NULL,那么语句的序列就被忽略了。
CREATE PROCEDURE p_1_7_3_5
AS
x NUMBER := 5;
y NUMBER := NULL;
BEGIN
IF x != y THEN -- yields NULL, not TRUE
DBMS_OUTPUT.PUT_LINE('x != y'); -- not run
ELSIF x = y THEN -- also yields NULL
DBMS_OUTPUT.PUT_LINE('x = y');
ELSE
DBMS_OUTPUT.PUT_LINE
('Can''t tell if x and y are equal or not.');
END IF;
END;
/
--Result:
--Can't tell if x and y are equal or not.
★相等比较中的NULL值
在本例中,您可能期望运行的语句序列,因为a和b看起来是相等的。但是,同样的,这是未知的,所以 IF条件产生了NULL,那么语句的序列就被忽略了。
CREATE PROCEDURE p_1_7_3_6
AS
a NUMBER := NULL;
b NUMBER := NULL;
BEGIN
IF a = b THEN -- yields NULL, not TRUE
DBMS_OUTPUT.PUT_LINE('a = b'); -- not run
ELSIF a != b THEN -- yields NULL, not TRUE
DBMS_OUTPUT.PUT_LINE('a != b'); -- not run
ELSE
DBMS_OUTPUT.PUT_LINE('Can''t tell if two NULLs are equal');
END IF;
END;
/
--Result:
--Can't tell if two NULLs are equal
★NOT NULL等于NULL
在本例中,两个IF语句似乎是等价的。但是,如果x或y有一个是NULL,那么第一个IF语句将y的值赋值给high,而第二个if语句将x的值赋值为high。
CREATE PROCEDURE p_1_7_3_7 AS
x INTEGER := 2;
Y INTEGER := 5;
high INTEGER;
BEGIN
IF (x > y) -- If x or y is NULL, then (x > y) is NULL
THEN high := x; -- run if (x > y) is TRUE
ELSE high := y; -- run if (x > y) is FALSE or NULL
END IF;
IF NOT (x > y) -- If x or y is NULL, then NOT (x > y) is NULL
THEN high := y; -- run if NOT (x > y) is TRUE
ELSE high := x; -- run if NOT (x > y) is FALSE or NULL
END IF;
END;
/
★更改逻辑运算符的运算顺序
第三次调用和第一次调用在逻辑上等价于第三次调用中的圆括号,只提高了可读性。第二个调用中的括号将更改运算顺序。
CREATE OR REPLACE PROCEDURE p_1_7_3_8
AS
x boolean :=true;
y boolean :=false;
BEGIN
if NOT x AND y then
DBMS_OUTPUT.PUT_LINE('NOT x AND y is true');
else
DBMS_OUTPUT.PUT_LINE('NOT x AND y is false');
end if;
if NOT (x AND y) then
DBMS_OUTPUT.PUT_LINE('NOT (x AND y) is true');
else
DBMS_OUTPUT.PUT_LINE('NOT (x AND y) is false');
end if;
if (NOT x) AND y then
DBMS_OUTPUT.PUT_LINE('(NOT x) AND y is true');
else
DBMS_OUTPUT.PUT_LINE('(NOT x) AND y is false');
end if;
END;
/
--Result:
--NOT x AND y is false
--NOT (x AND y) is true
--(NOT x) AND y is false
短路计算
当计算一个逻辑表达式的时候,PL/SQL使用短路计算。一旦能够确认表达式的值,则就不进行后续计算了。
CREATE PROCEDURE p_1_7_4
AS
on_hand INTEGER := 0;
on_order INTEGER := 100;
BEGIN
-- Does not cause divide-by-zero error;
-- evaluation stops after first expression
IF (on_hand = 0) OR ((on_order / on_hand) < 5) THEN
DBMS_OUTPUT.PUT_LINE('On hand quantity is zero.');
END IF;
END;
/
--Result:
--On hand quantity is zero.
比较运算符
比较操作符用于一个表达式和另外一个进行比较。结果为TRUE、FALSE、NULL。当一个表达式为NULL,比较的结果也为NULL。
比较操作符
Operator | Meaning |
---|---|
= | equal to |
<>, !=, ~=, ^= | not equal to |
< | less than |
> | greater than |
<= | less than or equal to |
>= | greater than or equal to |
★关系运算符的表达式
这个例子输出使用关系运算符比较算术值的表达式的值。
CREATE OR REPLACE PROCEDURE p_1_7_5_1
AS
BEGIN
if (2 + 2 ^= 4) then
DBMS_OUTPUT.PUT_LINE('(2 + 2 ^= 4) is true');
else
DBMS_OUTPUT.PUT_LINE('(2 + 2 ^= 4) is false');
end if;
END;
/
--Result:
--(2 + 2 ^= 4) is false
★LIKE运算表达式
字符串'Johnson'匹配模式'J%s_n',但不是'J%s_N',就像这个例子所显示的那样。
CREATE PROCEDURE compare(value VARCHAR2, pattern VARCHAR2)
IS
BEGIN
IF value LIKE pattern THEN
DBMS_OUTPUT.PUT_LINE ('TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE ('FALSE');
END IF;
END;
/
call compare('Johnson', 'J%s_n');
call compare('Johnson', 'J%S_N');
--Result:
--TRUE
--FALSE
★转义字符模式
这个例子使用反斜杠作为转义字符,因此字符串中的百分号不作为通配符。
CREATE PROCEDURE half_off (sale_sign VARCHAR2)
IS
BEGIN
IF sale_sign LIKE '50\% off!' ESCAPE '\' THEN
DBMS_OUTPUT.PUT_LINE ('TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE ('FALSE');
END IF;
END;
/
call half_off('Going out of business!');
call half_off('50% off!');
--Result:
--FALSE
--TRUE
★BETWEEN运算表达式
这个例子输出包含BETWEEN运算符的表达式的值。
CREATE OR REPLACE PROCEDURE p_1_7_5_4
AS
BEGIN
if 2 BETWEEN 1 AND 3 then
DBMS_OUTPUT.PUT_LINE('2 BETWEEN 1 AND 3 is true');
else
DBMS_OUTPUT.PUT_LINE('2 BETWEEN 1 AND 3 is false');
end if;
END;
/
--Result:
--2 BETWEEN 1 AND 3 is true
★IN运算表达式
这个例子输出包含IN运算符的表达式的值。
CREATE OR REPLACE PROCEDURE p_1_7_5_5
AS
letter VARCHAR2(1) := 'm';
BEGIN
if letter IN ('a', 'b', 'c') then
DBMS_OUTPUT.PUT_LINE('letter IN (a, b, c) is true');
else
DBMS_OUTPUT.PUT_LINE('letter IN (a, b, c) is false');
end if;
END;
/
--Result:
- letter IN (a, b, c) is false
★有NULL的IN运算集
这个示例显示了当集合包含NULL值时发生的情况。
CREATE OR REPLACE PROCEDURE p_1_7_5_6
AS
a INTEGER; -- Initialized to NULL by default
b INTEGER := 10;
c INTEGER := 100;
BEGIN
if (100 IN (a, b,c)) then
DBMS_OUTPUT.PUT_LINE('(100 IN (a, b,c)) is true');
else
DBMS_OUTPUT.PUT_LINE('(100 IN (a, b,c)) is false');
end if;
END;
/
--Result:
--100 IN (a, b, c) is true
算术运算符
★MOD运算符
MOD运算符用于返回n1 除以 n2 的余数。如果 n2 为 0,则返回 n1。
参数说明:
元素 | 描述 | 限制 | 语法 |
---|---|---|---|
n1 | 被除数 | 可以是任何数值类型或者可以隐式转换成数值类型的其他数据类型。 | 表达式 |
n2 | 除数 | 可以是任何数值类型或者可以隐式转换成数值类型的其他数据类型。 | 表达式 |
例如,函数中使用mod运算符:
SQL>create or replace function f1(i int)
return int
is
result int;
begin
result :=i mod 3;
return result;
end ;
/
布尔表达式
在SQL语句中,布尔表达式允许您在表中指定受声明影响。在过程语句中,布尔表达式是一个总能返回TURE或FLASE或NULL的表达式。一个简单的布尔表达式可以有布尔值、常量、变量组成。常见形式如下:
NOT boolean_expression
boolean_expression relational_operator boolean_expression
boolean_expression { AND | OR } boolean_expression
通常,布尔表达式由逻辑运算符AND、OR和NOT连接。布尔表达式总是产生TRUE、FALSE或NULL。
在这个例子中,循环中的条件是等价的。
CREATE PROCEDURE p_1_7_6
AS
done BOOLEAN;
BEGIN
-- These WHILE loops are equivalent
done := FALSE;
WHILE done = FALSE LOOP
done := TRUE;
END LOOP;
done := FALSE;
WHILE NOT (done = TRUE) LOOP
done := TRUE;
END LOOP;
done := FALSE;
WHILE NOT done
LOOP
done := TRUE;
END LOOP;
END;
/
Case表达式
语法
CASE selector
WHEN selector_value_1 THEN result_1
WHEN selector_value_2 THEN result_2
...
WHEN selector_value_n THEN result_n
[ ELSE
else_result ]
END
一个CASE表达式从一个或多个方案中选择一个。一旦有一个条件满足,剩下的分支就不执行了。
★简单的CASE表达
这个示例将一个简单CASE表达式的值赋给变量appraisal,selector值是 grade。
CREATE PROCEDURE p_1_7_7_1
AS
grade CHAR(1) := 'B';
appraisal VARCHAR2(20);
BEGIN
appraisal :=
CASE grade
WHEN 'A' THEN 'Excellent'
WHEN 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good'
WHEN 'D' THEN 'Fair'
WHEN 'F' THEN 'Poor'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal);
END;
/
--Result:
--Grade B is Very Good
★WHEN NULL条件下的简单的CASE表达式
如果selector值为NULL,则不能在WHEN NULL条件下被匹配,相反,可以在WHEN boolean_expression IS NULL条件下使用CASE表达式搜索。
CREATE PROCEDURE p_1_7_7_2
AS
grade CHAR(1); -- NULL by default
appraisal VARCHAR2(20);
BEGIN
appraisal :=
CASE grade
WHEN NULL THEN 'No grade assigned'
WHEN 'A' THEN 'Excellent'
WHEN 'B' THEN 'Very Good'
WHEN 'C' THEN 'Good'
WHEN 'D' THEN 'Fair'
WHEN 'F' THEN 'Poor'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal);
END;
/
--Result:
--Grade is No such grade
★搜寻CASE表达式
语法
CASE
WHEN boolean_expression_1 THEN result_1
WHEN boolean_expression_2 THEN result_2
...
WHEN boolean_expression_n THEN result_n
[ ELSE
else_result ]
END]
这个示例将搜寻CASE表达式的值赋给变量appraisal。
CREATE FUNCTION attends_this_school (id NUMBER)
RETURN BOOLEAN IS
a BOOLEAN:=TRUE;
BEGIN
RETURN a;
END;
/
CREATE PROCEDURE p_1_7_7_3 AS grade CHAR(1) := 'B';
appraisal VARCHAR2(120);
id NUMBER := 8429862;
attendance NUMBER := 150;
min_days CONSTANT NUMBER := 200;
BEGIN
appraisal :=
CASE
WHEN attends_this_school(id) = FALSE
THEN 'Student not enrolled'
WHEN grade = 'F' OR attendance < min_days
THEN 'Poor (poor performance or bad attendance)'
WHEN grade = 'A' THEN 'Excellent'
WHEN grade = 'B' THEN 'Very Good'
WHEN grade = 'C' THEN 'Good'
WHEN grade = 'D' THEN 'Fair'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE('Result for student ' || id || ' is ' || appraisal);
END;
/
--Result:
--Result for student 8429862 is Poor (poor performance or bad attendance)
★WHEN ... IS NULL条件下的搜寻case语句
这个示例使用一个搜索的CASE表达式来解决例2.2.51中的问题。
CREATE PROCEDURE p_1_7_7_4
AS
grade CHAR(1); -- NULL by default
appraisal VARCHAR2(20);
BEGIN
appraisal :=
CASE
WHEN grade IS NULL THEN 'No grade assigned'
WHEN grade = 'A' THEN 'Excellent'
WHEN grade = 'B' THEN 'Very Good'
WHEN grade = 'C' THEN 'Good'
WHEN grade = 'D' THEN 'Fair'
WHEN grade = 'F' THEN 'Poor'
ELSE 'No such grade'
END;
DBMS_OUTPUT.PUT_LINE ('Grade ' || grade || ' is ' || appraisal);
END;
/
--Result:
--Grade is No grade assigned
★在比较和条件语句中处理NULL值
- 涉及空值的比较总是产生空值
- 将逻辑运算符NOT应用于空值会产生空值
- 在条件控制语句中,如果条件为空,则不执行语句序列
- 如果简单CASE语句或CASE表达式中的表达式产生NULL,则无法通过使用WHEN NULL进行匹配。相反,使用搜索的CASE语法当表达式为空时