Oracle PL/SQL Programming 第8章:Strings 读书笔记

总的目录和进度,请参见开始读 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

使用RPADLPDD

可以单个字符或字符串填充;指定的长度若小于需填充的字符串,则会造成截断:

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则用于移除。

LTRIMRTRIM可以移除单个字符或字符集合。

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

REGEXP_COUNT

Replacing text

REGEXP_REPLACE

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

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,所有字母均大写。

相关推荐
Hacker_LaoYi30 分钟前
SQL注入的那些面试题总结
数据库·sql
Hacker_LaoYi2 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
独行soc3 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
独行soc4 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍08-基于时间延迟的SQL注入(Time-Based SQL Injection)
数据库·sql·安全·渗透测试·漏洞挖掘
百度智能云技术站5 小时前
广告投放系统成本降低 70%+,基于 Redis 容量型数据库 PegaDB 的方案设计和业务实践
数据库·redis·oracle
清平乐的技术专栏5 小时前
Hive SQL 查询所有函数
hive·hadoop·sql
梦想平凡6 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
夏木~8 小时前
Oracle 中什么情况下 可以使用 EXISTS 替代 IN 提高查询效率
数据库·oracle
吴冰_hogan9 小时前
MySQL InnoDB 存储引擎 Redo Log(重做日志)详解
数据库·oracle
cmdch201710 小时前
Mybatis加密解密查询操作(sql前),where要传入加密后的字段时遇到的问题
数据库·sql·mybatis