总的目录和进度,请参见开始读 Oracle PL/SQL Programming 第6版
具有字符数据类型的变量存储文本并由字符函数操作。
本章重点讨论单字节字符集,不涉及Unicode 或多字节字符集,不涉及CLOB(字符大对象)和 LONG。
String Datatypes
Oracle 支持四种字符串数据类型:
定长 | 变长 | |
---|---|---|
数据库字符集 | CHAR | VARCHAR |
国家字符集 | NCHAR | NVARCHAR2 |
建议永远不要使用CHAR和NCHAR。
The VARCHAR2 Datatype
sql
variable_name VARCHAR2 (max_length [CHAR | BYTE]);
对于PL/SQL,如果单位是BYTE,则最大为32,767。对于SQL,12c前最大4000,12c后32,767字节,但要设置MAX_SQL_STRING_SIZE参数为EXTENDED。
多字节字符集建议以CHAR为单位,单位为CHAR时,实际的BYTE与字符集有关。
当省略BYTE或CHAR时,实际的单位由初始化参数NLS_LENGTH_SEMANTICS 确定:
sql
SQL> show parameter NLS_LENGTH_SEMANTICS
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_length_semantics string BYTE
您可以通过查询 NLS_SESSION_PARAMETERS 来确定当前设置。
sql
SQL> select * from NLS_SESSION_PARAMETERS;
PARAMETER VALUE
__________________________ _______________________________
NLS_LANGUAGE AMERICAN
NLS_TERRITORY AMERICA
NLS_CURRENCY $
NLS_ISO_CURRENCY AMERICA
NLS_NUMERIC_CHARACTERS .,
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD-MON-RR
NLS_DATE_LANGUAGE AMERICAN
NLS_SORT BINARY
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY $
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE
17 rows selected.
The CHAR Datatype
CHAR 数据类型指定固定长度的字符串。
若不指定长度,则默认为1。
String Subtypes
子类型是为了提供与 ANSI SQL 标准的兼容性。一般用不到。
子类型 | 对应的PL/SQL类型 |
---|---|
CHAR VARYING | VARCHAR2 |
CHARACTER | CHAR |
CHARACTER VARYING | VARCHAR2 |
NATIONAL CHAR | NCHAR |
NATIONAL CHAR VARYING | NVARCHAR2 |
NATIONAL CHARACTER | NCHAR |
NATIONAL CHARACTER VARYING | NVARCHAR2 |
NCHAR VARYING | NVARCHAR2 |
STRING | VARCHAR2 |
VARCHAR | VARCHAR2 |
不要使用 VARCHAR; 使用VARCHAR2。
Working with Strings
使用字符串主要是使用 Oracle 丰富的内置字符串函数库来操作它们。
Specifying String Constants
sql
'You are welcome!'
-- 以下使用了转义,并等同
'You''re welcome!'
q'!You're welcome!!'
q'{You're welcome!}'
当您使用 q 前缀时,您仍然必须将整个字符串括在单引号内。 紧跟在第一个引号后面的字符将成为字符串的分隔符。 如果起始分隔符是 [、{、< 或 () 之一,则结束分隔符必须分别是 ]、}、> 或 )。
通常,字符串常量使用数据库字符集表示。 如果将这样的字符串常量分配给 NCHAR 或 NVARCHAR2 变量,则该常量将隐式转换为国家字符集。 数据库会在必要时执行此类转换,您无需担心它们。 但是,有时您可能需要显式指定要在国家字符集中表示的字符串常量。 您可以使用 n 前缀来执行此操作:
sql
n'Pils vom faß: 1₠'
u前缀表示国家字符集+Unicode:
sql
u'Pils vom fa\00DF: 1\20AC'
&在SQL Plus和SQL Developer中有特殊含义,表示替换变量,可以SET DEFINE OFF禁止。例如:
sql
select '1 & 2' from dual;
set define off
select '1 & 2' from dual;
Using Nonprintable Characters
使用CHR函数:
sql
SQL> select 1 || CHR(10) || 2 from dual;
1||
---
1
2
CHR函数的逆操作为ASCII。
sql
SQL> select ASCII('A') from dual;
ASCII('A')
----------
65
SQL> select CHR(65) from dual;
C
-
A
Concatenating Strings
两种方法,||
或CONCAT函数。
如CONCAT函数两参数类型不一,返回数据类型将是保留最多信息的那个。
两个参数以上可以使用多个CONCAT函数嵌套。
Dealing with Case
比较时不区分大小写
若希望比较时不区分大小写,可以强制字符串全部大写或小写(LOWER或UPPER函数)。
可以使用初始化参数 NLS_COMP 和 NLS_SORT 来使所有字符串比较不区分大小写。 将 NLS_COMP 参数设置为 LINGUISTIC,这将告诉数据库使用 NLS_SORT 进行字符串比较。 然后将 NLS_SORT 设置为不区分大小写的设置,例如 BINARY_CI 或 XWEST_EUROPEAN_CI。 尾随 _CI 表示不区分大小写。
sql
SQL> show parameter nls_comp
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_comp string BINARY
SQL> SELECT LEAST ('JONATHAN','Jonathan','jon') FROM dual;
LEAST('J
--------
JONATHAN
SQL> show parameter nls_comp
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_comp string BINARY
SQL> show parameter nls_sort
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
nls_sort string
SQL> SELECT LEAST ('JONATHAN','Jonathan','jon') FROM dual;
LEAST('J
--------
JONATHAN
SQL> ALTER SESSION SET NLS_COMP=LINGUISTIC;
Session altered.
SQL> ALTER SESSION SET NLS_SORT=BINARY_CI;
Session altered.
SQL> SELECT LEAST ('JONATHAN','Jonathan','jon') FROM dual;
LEA
---
jon
NLS_COMP 和 NLS_SORT 设置会影响您执行的所有字符串操作。 这些设置会"保留",直到您更改它们或终止会话为止。
Oracle 还支持不区分重音的排序,您可以通过将 _AI(而不是 _CI)附加到排序名称来获得这种排序。 要查找语言排序名称的完整列表,请参阅 Oracle 数据库全球化支持指南。 该指南还详细解释了 NLS_COMP 和 NLS_SORT 的操作。
不区分大小写和索引
如果设置 NLS_COMP=LINGUISTIC 和 NLS_SORT=BINARY_CI 来启用不区分大小写时,以下SQL使用全表扫描而不使用定义在last_name列上的索引:
sql
SELECT * FROM employees WHERE last_name = lname
可以定义基于函数的索引以避免以上问题:
sql
CREATE INDEX last_name_ci ON EMPLOYEES (NLSSORT(last_name, 'NLS_SORT=BINARY_CI'))
将字符串中的每个单词大写
INITCAP函数。
Traditional Searching, Extracting, and Replacing
查找位置用:INSTR
提取字符串用:SUBSTR
从1或-1开始计数:
sql
select substr('abcdefg', 2);
SUBSTR
------
bcdefg
SQL> select substr('abcdefg', -2);
SU
--
fg
注意INSTR也可以反向查找,但返回的位置是正数。
sql
SQL> select instr('abcdabcd', 'bc');
INSTR('ABCDABCD','BC')
----------------------
2
SQL> select instr('abcdabcd', 'bc', 4);
INSTR('ABCDABCD','BC',4)
------------------------
6
SQL> select instr('abcdabcd', 'bc', -1);
INSTR('ABCDABCD','BC',-1)
-------------------------
6
SQL> select instr('abcdabcd', 'bc', -2);
INSTR('ABCDABCD','BC',-2)
-------------------------
6
-- 下面这个不太好理解
-- 是从倒数第3个字符即b开始查找,查找的方向是反向,但匹配是按正向,因此返回6
SQL> select instr('abcdabcd', 'bc', -3);
INSTR('ABCDABCD','BC',-3)
-------------------------
6
替换用:REPLACE
sql
select REPLACE('Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec', ',', chr(10)) as mon from dual;
Padding
可以单个字符或字符串填充;指定的长度若小于需填充的字符串,则会造成截断:
sql
SQL> select lpad('abcdefg', 4) from dual;
LPAD
----
abcd
SQL> select lpad('abcdefg', 10, '.') from dual;
LPAD('ABCD
----------
...abcdefg
Trimming
LPAD 和 RPAD用于填充,而TRIM、LTRIM 和 RTRIM则用于移除。
TRIM是为了兼容ISO SQL 标准,可从左,右或两端移除。但其只能移除单个字符:
sql
SQL> select trim('.' from '.abcd.');
TRIM
----
abcd
SQL> select trim('.a' from '.abcd.');
select trim('.a' from '.abcd.')
*
ERROR at line 1:
ORA-30001: trim set should have only one character
Help: https://docs.oracle.com/error-help/db/ora-30001/
Regular Expression Searching, Extracting, and Replacing
正则表达式为您提供了一种模式语言,您可以使用它来描述要查找和操作的文本。
Oracle的正则表达式基于POSIX标准,又做了扩展,功能更强。详见Oracle Regular Expression Support
例如,^([a-z A-Z]*,)+([a-z A-Z]*){1}$
表示以逗号分隔的单词列表,如Jan, Feb, Mar, Apr, May
。
Detecting a pattern
REGEXP_LIKE返回TRUE和FALSE。
LIKE函数则是简单匹配,用_
或%
。
Locating a pattern
REGEXP_INSTR,是INSTR的增强。返回匹配的字符串或NULL。
Extracting text matching a pattern
REGEXP_SUBSTR,是SUBSTR的增强。
Counting regular expression matches
Replacing text
Grokking greediness
根据Quora的解释:
Grok意思是充分理解并整合先前的知识。 这个词出自罗伯特·A·海因莱因的科幻小说《异乡的陌生人》。
在某种程度上,"你明白吗?" 类似于俚语"明白了吗?"
这里所说的贪婪是指,正则表达式的每个元素将匹配尽可能多的字符。
例如对于字符串'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'
,正则表达式.*
将匹配为''Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov'
,而不仅仅是最开始部分的'Jan,'
。
sql
SQL> select REGEXP_SUBSTR('Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec', '.*,') from dual;
REGEXP_SUBSTR('JAN,FEB,MAR,APR,MAY,JUN,JUL,A
--------------------------------------------
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,
-- ^ 表示 排除
SQL> select REGEXP_SUBSTR('Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec', '[^,]*,') from dual;
REGE
----
Jan,
可以在*号后加?号指定为非贪婪算法:
sql
SQL> select REGEXP_SUBSTR('Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec', '.*?,') from dual;
REGE
----
Jan,
非贪婪量词?实现了尽快地匹配,而不是尽可能多地匹配。
Learning more about regular expressions
- Oracle Database Application Developer's Guide---Fundamentals 第4章 或者最新版本看这里。
- Mastering Oracle SQL, 2nd Edition,亚马逊4.5星
- Mastering Regular Expressions, 3rd Edition,亚马逊4.5星
- Oracle Regular Expressions Pocket Reference,亚马逊4星
Working with Empty Strings
注意,Oracle 数据库将空字符串(''
)视为 NULL,特别是对于在使用其他数据库之后才使用 Oracle 的人来说。 这与 ISO SQL 标准相反,该标准将空字符串和 NULL 区别开来。
sql
/* File on web: empty_is_null.sql */
DECLARE
empty_varchar2 VARCHAR2(10) := '';
empty_char CHAR(1) := '';
BEGIN
IF empty_varchar2 IS NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_varchar2 is NULL');
END IF;
IF '' IS NULL THEN
DBMS_OUTPUT.PUT_LINE(''''' is NULL');
END IF;
IF empty_char IS NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_char is NULL');
ELSIF empty_char IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('empty_char is NOT NULL');
END IF;
END;
输出为:
sql
empty_varchar2 is NULL
'' is NULL
empty_char is NOT NULL
因此编程时在比较时需特别小心。因为 NULL 永远不会等于或不等于任何其他值。
Mixing CHAR and VARCHAR Values
Database-to-variable conversion
当您从 CHAR 数据库列中 SELECT 或 FETCH 数据到 VARCHAR2 变量中时,会保留尾随空格。 如果您从 VARCHAR2 数据库列 SELECT 或 FETCH 到 CHAR 变量,PL/SQL 会自动用空格填充该值,使其达到最大长度。
Variable-to-database conversion
和上面的规则是一致的。
当您将 CHAR 变量插入或更新到 VARCHAR2 数据库列时,SQL 内核在执行更改之前不会修剪尾随空格。
当您将 VARCHAR2 变量插入或更新到 CHAR 数据库列时,SQL 内核会自动用空格填充可变长度字符串,使其达到创建表时指定的最大(固定)长度,然后存入数据库。
String comparisons
两个字符串变量比较的规则:
- 如果两个都是 CHAR 变量,则使用空白填充比较(短的那个一致填充到长的那个定义的长度)。
- 如果其中一个是可变长度(如VARCHAR2),则 PL/SQL 执行非空白填充比较。此规则也同样适用于涉及两个以上变量的表达式以及涉及 IN 运算符的表达式
sql
DECLARE
c10 CHAR(10)
:= 'welcome';
c15 CHAR(15)
:= 'welcome';
vc15 VARCHAR2(15)
:= 'welcome';
BEGIN
-- Compare two CHARs, so blank-padding is used
IF c10 = c15 THEN
DBMS_OUTPUT.PUT_LINE ('first comparison is TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE ('first comparison is FALSE');
END IF;
-- Compare a CHAR and a VARCHAR2, so nonblank-padding is used
IF c15 = vc15 THEN
DBMS_OUTPUT.PUT_LINE ('second comparison is TRUE');
ELSE
DBMS_OUTPUT.PUT_LINE ('second comparison is FALSE');
END IF;
END;
输出:
sql
first comparison is TRUE
second comparison is FALSE
Character functions and CHAR arguments
字符函数是一种采用一个或多个字符值作为参数并返回字符值或数字值的函数。 当字符函数返回字符值时,该值始终为 VARCHAR2(可变长度)类型。
String Function Quick Reference
以下是常用的,详见SQL Language Reference
ASCII(char)- 返回 char 第一个字符在数据库字符集中的十进制表示形式。
ASCIISTR(char) - 将任何字符集中的字符串或解析为字符串的表达式作为其参数,并返回数据库字符集中该字符串的 ASCII 版本。
CHR(n) 返回与 n 等效的二进制字符作为数据库字符集或国家字符集(如果指定 USING NCHAR_CS)中的 VARCHAR2 值。
COMPOSE(char) 将字符值 char 作为其参数,并返回对其应用 Unicode 规范组合(如 Unicode 标准定义 D117 中所述)的结果。
CONCAT(char1, char2) CONCAT 返回 char1 与 char2 的拼接。
CONVERT(char1, dest_char_set ) 将字符串从一种字符集转换为另一种字符集。
DECOMPOSE(string) 将字符值字符串作为其第一个参数,并返回对其应用其中一个 Unicode 分解的结果。
GREATEST(expr) GREATEST 返回一个或多个表达式列表中最大的一个。
INITCAP(char) INITCAP 返回 char,每个单词的第一个字母大写,所有其他字母小写。
INSTR(string, substring) 函数在字符串中搜索子字符串。
LEAST(expr) 返回一个或多个表达式列表中的最小值。
LENGTH(char) 返回char的长度。
LOWER(char) 返回 char,所有字母均小写。
LPAD(expr1, n, expr2) 返回 expr1,用 expr2 中的字符序列向左填充长度为 n 个字符。 此函数对于格式化查询的输出很有用。
LTRIM(char) 从 char 的左端删除 set 中包含的所有字符。
NCHR(number) 返回与国家字符集中的数字等效的二进制字符。
NLS_INITCAP(char) 返回 char,每个单词的第一个字母大写,所有其他字母小写。 单词由空格或非字母数字字符分隔。
NLS_LOWER,NLS_UPPER,NLSSORT类似。
REGEXP_COUNT, REGEXP_INSTR, REGEXP_LIKE, REGEXP_REPLACE, REGEXP_SUBSTR系列。
REPLACE(char, search_string, replacement_string) REPLACE 返回 char,其中每次出现的 search_string 都替换为 replacement_string。
RPAD(expr1, n, expr2) 返回 expr1,用 expr2 右填充到长度 n 个字符,根据需要复制多次。
RTRIM(char, set) 从 char 的右端删除集中出现的所有字符。
SOUNDEX(char) 返回包含 char 的语音表示形式的字符串。 此功能可让您比较拼写不同但英语发音相似的单词。
SUBSTR(char, position, substring_length) 函数返回 char 的一部分,从字符position开始,substring_length 个字符长。
TO_CHAR() (字符)将 NCHAR、NVARCHAR2、CLOB 或 NCLOB 数据转换为数据库字符集。 返回的值始终是 VARCHAR2。
TO_MULTI_BYTE(char) 返回 char 并将其所有单字节字符转换为相应的多字节字符。 char 可以是 CHAR、VARCHAR2、NCHAR 或 NVARCHAR2 数据类型。 返回值的数据类型与 char 相同。
sql
SQL> SELECT dump(TO_MULTI_BYTE( 'A')) FROM DUAL;
DUMP(TO_MULTI_BYTE('A'))
------------------------
Typ=1 Len=3: 239,188,161
SQL> SELECT dump('A') FROM DUAL;
DUMP('A')
----------------
Typ=96 Len=1: 65
TO_NCHAR() 将数据库字符集中的数据转换为国家字符集中的等效表示形式。
TO_SINGLE_BYTE(char) 返回 char ,其中所有多字节字符都转换为相应的单字节字符。
TRANSLATE(expr, from_string, to_string) 返回 expr,并将 from_string 中每个字符的所有出现位置替换为 to_string 中对应的字符。
TRIM不说了。
UNISTR(string) 将文本文字或解析为字符数据的表达式作为其参数,并以国家字符集返回它。
UPPER(char) UPPER 返回 char,所有字母均大写。