ORACLE官方SQL语言参考笔记之Oracle SQL的基本元素篇(第三章-第二节-数据类型比较规则)

本文简述

此书下载方法:加入群技术交流群(免费)699712384,文件夹为ORACLE官方文档中 
CSDN技术网址 
简书技术网址 
ORACLE官网教程地址 
书名:

中文名:《SQL语言参考笔记》

英文名:《SQL Language Reference》

作者:二次猿

时间:阅读于2018年3月21日

准备工作:详情见:具体可以参考简书和二次猿公众号常用表

注意事项:跳过基本概念和非重要内容,重点举例说明,并且加粗,部分内容可能在其他章节会再次详细介绍,表格如果排版不美观,可以复制到excle进行直观展示,代码部分根据实际情况注释和说明

数据类型比较规则

本节介绍 Oracle 数据库如何比较每个数据类型的值。

数值

一个较大的值被认为大于一个小数值。所有负数都小于零和所有正数。因此,-1 小于 100;-100 小于-1。

浮点值NaN (不是数字) 大于任何其他数值, 并且等于自身。

日期值

以后的日期被认为大于较早的时间。例如, "29-2005" 的日期小于 "05-简-2006" 和 ' 05-简-2006 1:35pm ', 大于 ' 05-简-2005 10:09am '。

字符值

字符值是根据两种措施进行比较的:

  • 二进制或语言排序

  • 空白填充或 nonpadded 比较语义

下面的小节描述了这两项措施。

二进制和语言比较

在二进制比较 (即默认值) 中, Oracle 根据数据库字符集中字符的数字代码的串联值对字符串进行比较。如果一个字符的数值比字符集中的其他值更大, 则它大于另一个。甲骨文认为空白小于任何字符, 这在大多数字符集中都是正确的。

这些是一些常用字符集:

  • 7位 ASCII (美国信息交换标准代码)

  • EBCDIC 代码 (扩展二进制编码的十进制互换代码)

  • ISO 8859/1 (国际标准化组织)

  • JEUC 日本扩展 UNIX

如果数字代码的二进制序列与所比较的字符的语言序列不匹配, 则语言比较很有用。如果NLS_SORT参数具有BINARY以外的设置, 并且NLS_COMP参数设置为LINGUISTIC, 则使用语言比较。在语言排序中, 所有 SQL 排序和比较都基于NLS_SORT指定的语言规则。.

空白填充和 Nonpadded 比较语义

使用空白填充语义, 如果两个值有不同的长度, 则 Oracle 首先将空白添加到较短的末尾, 以便它们的长度相等。然后, Oracle 将值的字符与不同的第一个字符进行比较。在第一个不同位置具有较大字符的值被视为更大。如果两个值没有不同的字符, 则它们被视为相等。此规则意味着如果两个值仅在尾随空格的数量上不同, 则它们是相等的。只有当比较中的两个值都是数据类型CHAR、 NCHAR、文本文字或USER函数返回的值的表达式时, Oracle 才使用空白填充比较语义。

使用 nonpadded 语义, Oracle 将两个值的字符与不同的第一个字符进行比较。该位置中具有较大字符的值被视为更大。如果两个不同长度的值与较短的末尾相同, 则更长的值被视为较大。如果两个相等长度的值没有不同的字符, 则将这些值视为相等。每当比较中的一个或两个值都具有数据类型VARCHAR2NVARCHAR2时, Oracle 就使用 nonpadded 比较语义.

使用不同的比较语义比较两个字符值的结果可能会有所不同。下面的表显示了使用每个比较语义比较五对字符值的结果。通常, 空白填充和 nonpadded 比较的结果是相同的。表中的最后一个比较说明了空白填充和 nonpadded 比较语义之间的差异。

空白填充 Nonpadded
'ac' > 'ab' 'ac' > 'ab'
'ab' > 'a  ' 'ab' > 'a   '
'ab' > 'a' 'ab' > 'a'
'ab' = 'ab' 'ab' = 'ab'
'a ' = 'a' 'a ' > 'a'

ASCII 和 EBCDIC 字符集的部分显示在表 3-8表 3-9中。大写和小写字母不相等。字符集的字符的数字值可能与特定语言的语言序列不匹配。

表 3-8 ASCII 字符集

象征 十进制值 象征 十进制值

blank

32

;

59

!

33

<

60

"

34

=

61

#

35

>

62

$

36

?

63

%

37

@

64

&

38

A-Z

65-90

'

39

[

91

(

40

\

92

)

41

]

93

*

42

^

94

+

43

_

95

,

44

'

96

-

45

a-z

97-122

.

46

{

123

/

47

|

124

0-9

48-57

}

125

:

58

~

126


表 3-9 EBCDIC 字符集

象征 十进制值 象征 十进制值

blank

64

%

108

¢

74

_

109

.

75

>

110

<

76

?

111

(

77

:

122

+

78

#

123

|

79

@

124

&

80

'

125

!

90

=

126

$

91

"

127

*

92

a-i

129-137

)

93

j-r

145-153

;

94

s-z

162-169

ÿ

95

A-I

193-201

-

96

J-R

209-217

/

97

S-Z

226-233


对象值

使用两个比较函数之一 ( MAPORDER) 比较对象值。这两个函数比较对象类型实例, 但它们彼此很不相同。必须将这些函数指定为将与其他对象类型进行比较的任何对象类型的一部分。

Varrays 和嵌套表

嵌套表的比较在"比较条件"中描述.

数据类型优先级

Oracle 使用数据类型优先级来确定隐式数据类型转换, 下面的部分将对此进行讨论。Oracle 数据类型的优先级如下:

  • 日期时间和间隔数据类型

  • BINARY_DOUBLE

  • BINARY_FLOAT

  • NUMBER

  • 字符数据类型

  • 所有其他内置数据类型

数据转换

通常, 表达式不能包含不同数据类型的值。例如, 表达式不能将5乘以 10, 然后添加 "JAMES"。但是, Oracle 支持将值从一种数据类型的隐式和显式转换为另一种。

隐式和显式数据转换

Oracle 建议您指定显式转换, 而不是依赖于隐式或自动转换, 原因如下:

  • 使用显式数据类型转换函数时, SQL 语句更易于理解。

  • 隐式数据类型转换可能会对性能产生负面影响, 特别是当列值的数据类型转换为常量而不是其他方法时。

  • 隐式转换依赖于它发生的上下文, 并且在每个情况下可能无法以相同的方式工作。例如, 从 datetime 值到VARCHAR2值的隐式转换可能会根据NLS_DATE_FORMAT参数的值返回意外年份。

  • 隐式转换的算法会在软件发行版和 Oracle 产品之间发生变化。显式转换的行为更可预测。

  • 如果在索引表达式中出现隐式数据类型转换, 则 Oracle 数据库可能不使用该索引, 因为它是为预转换数据类型定义的。这可能会对性能产生负面影响。

隐式数据转换

当这样的转换有意义时, Oracle 数据库会自动将一个数据类型的值转换为另一个。

表 3-10是 Oracle 隐式转换的矩阵。该表显示所有可能的转换, 而不考虑转换的方向或它的上下文。有关这些细节的规则将在表中执行。

表3-10 隐式转换矩阵

  字符 VARCHAR2 NCHAR NVARCHAR2 日期 日期时间/间隔 数量 BINARY_FLOAT BINARY_DOUBLE 原始 ROWID Clob Blob NCLOB

字符

--

X

X

X

X

X

X

X

X

X

X

--

X

X

X

VARCHAR2

X

--

X

X

X

X

X

X

X

X

X

X

X

--

X

NCHAR

X

X

--

X

X

X

X

X

X

X

X

X

X

--

X

NVARCHAR2

X

X

X

--

X

X

X

X

X

X

X

X

X

--

X

日期

X

X

X

X

--

--

--

--

--

--

--

--

--

--

--

日期时间/间隔

X

X

X

X

--

--

--

--

--

X

--

--

--

--

--

数量

X

X

X

X

--

--

--

X

X

--

--

--

--

--

--

BINARY_FLOAT

X

X

X

X

--

--

X

--

X

--

--

--

--

--

--

BINARY_DOUBLE

X

X

X

X

--

--

X

X

--

--

--

--

--

--

--

X

X

X

X

--

X脚1

--

--

--

--

X

--

X

--

X

原始

X

X

X

X

--

--

--

--

--

X

--

--

--

X

--

ROWID

--

X

X

X

--

--

--

--

--

--

--

--

--

--

--

Clob

X

X

X

X

--

--

--

--

--

X

--

--

--

--

X

Blob

--

--

--

--

--

--

--

--

--

--

X

--

--

--

--

NCLOB

X

X

X

X

--

--

--

--

--

X

--

--

X

--

--


脚注1不能直接将LONG转换为INTERVAL, 但可以使用TO_CHAR(interval) 将LONG转换为VARCHAR2 , 然后将结果VARCHAR2值转换为INTERVAL.

以下规则控制隐式数据类型转换:

  • INSERTUPDATE操作期间, Oracle 将该值转换为受影响列的数据类型。

  • SELECTFROM操作期间, Oracle 将数据从列转换为目标变量的类型。

  • 在操作数值时, Oracle 通常会调整精度和刻度以允许最大容量。在这种情况下, 由此类操作产生的数值数据类型可能与基础表中找到的数值数据类型不同。

  • 将字符值与数字值进行比较时, Oracle 将字符数据转换为数值。

  • 字符值或NUMBER值和浮点数字值之间的转换可能不精确, 因为字符类型和NUMBER使用十进制精度表示数值, 浮点数字使用二进制精度。

  • CLOB值转换为字符数据类型 (如VARCHAR2) 或将BLOB转换为RAW数据时, 如果要转换的数据大于目标数据类型, 则数据库将返回错误。

  • 在从时间戳值转换为DATE值期间, 时间戳值的小数秒部分将被截断。当时间戳值的小数秒部分被舍入时, 此行为与 Oracle 数据库的早期版本不同。

  • BINARY_FLOATBINARY_DOUBLE的转换是精确的。

  • 如果BINARY_DOUBLE值使用BINARY_FLOAT支持的更多精度位, 则从BINARY_DOUBLEBINARY_FLOAT的转换是不精确的。.

  • 将字符值与DATE值进行比较时, Oracle 将字符数据转换为DATE.

  • 当您将 SQL 函数或运算符与它所接受的数据类型的参数一起使用时, Oracle 会将该参数转换为接受的数据类型。

  • 在进行分配时, Oracle 将等号 (=) 右侧的值转换为左侧分配的目标的数据类型。

  • 在串联操作期间, Oracle 从字符数据类型转换为CHARNCHAR.

  • 在对字符和字符数据类型进行算术运算和比较时, Oracle 根据需要将任何字符数据类型转换为数字、日期或 rowid。CHAR/VARCHAR2NCHAR/NVARCHAR2之间的算术运算中, Oracle 转换为NUMBER.

  • 大多数 SQL 字符函数都可以接受CLOB作为参数, 并且 Oracle 在CLOB和字符类型之间执行隐式转换。因此, 尚未启用CLOBs 的函数可以通过隐式转换接受CLOB在这种情况下, Oracle 在调用函数之前将CLOBs 转换为CHARVARCHAR2 。如果CLOB大于4000字节, 则 Oracle 只将前4000个字节转换为CHAR.

  • RAWLONGRAW数据转换为字符数据时, 二进制数据以十六进制形式表示, 其中一个十六进制字符表示RAW数据的每四位。有关详细信息, 请参阅"原始和长原始数据类型" 。

  • CHARVARCHAR2之间以及NCHARNVARCHAR2类型之间的比较可能需要不同的字符集。在这种情况下, 转换的默认方向是从数据库字符集设置为国家字符集。表 3-11显示了不同字符类型之间的隐式转换的方向。

表3-11 不同字符类型的转换方向

  为 CHAR VARCHAR2 NCHAR NVARCHAR2

从 CHAR

--

VARCHAR2

NCHAR

NVARCHAR2

从 VARCHAR2

VARCHAR2

--

NVARCHAR2

NVARCHAR2

从 NCHAR

NCHAR

NCHAR

--

NVARCHAR2

从 NVARCHAR2

NVARCHAR2

NVARCHAR2

NVARCHAR2

--


用户定义类型 (如集合) 不能隐式转换, 但必须使用CAST显式转换.。MULTISET.

隐式数据转换示例

文本文字示例文本文字 "10" 具有数据类型CHAR如果 Oracle 在数字表达式中显示为NUMBER数据类型, 则它将隐式地将其转换为以下语句:

SELECT salary + '10'
  FROM employees;

字符和数字值示例当条件比较字符值和NUMBER值时, Oracle 隐式地将字符值转换为NUMBER值, 而不是将NUMBER值转换为字符值。在下面的语句中, Oracle 隐式地将 "200" 转换为 200:

SELECT last_name
  FROM employees
  WHERE employee_id = '200';

日期示例在下面的语句中, Oracle 使用默认日期格式隐式地将 "24-JUN-06" 转换为DATEDD-MON-YY':

SELECT last_name
  FROM employees 
  WHERE hire_date = '24-JUN-06';

显式数据转换

可以使用 SQL 转换函数显式指定数据类型转换。表 3-12显示了将值从一种数据类型显式转换为另一种形式的 SQL 函数。

在 Oracle 可以执行隐式数据类型转换的情况下, 不能指定LONGLONG RAW值。例如, LONGLONG RAW值不能出现在具有函数或运算符的表达式中。有关LONGLONG RAW数据类型的限制的信息, 请参阅"长数据类型" 。

表3-12 显式类型转换

  CHAR,VARCHAR2,NCHAR,NVARCHAR2 到数字 到日期时间/间隔 到原始 ROWID 长, 长生 CLOB, NCLOB, BLOB BINARY_FLOAT BINARY_DOUBLE

从 CHAR, VARCHAR2, NCHAR, NVARCHAR2

TO_CHAR (char.)

TO_NCHAR (char.)

TO_NUMBER

TO_DATE

TO_TIMESTAMP

TO_TIMESTAMP_TZ

TO_YMINTERVAL

TO_DSINTERVAL

HEXTORAW

CHARTO­=ROWID

--

TO_CLOB

TO_NCLOB

TO_BINARY_FLOAT

TO_BINARY_DOUBLE

从数字

TO_CHAR (number)

TO_NCHAR (number)

--

TO_DATE

NUMTOYM- INTERVAL

NUMTODS- INTERVAL

--

--

--

--

TO_BINARY_FLOAT

TO_BINARY_DOUBLE

从日期时间/间隔

TO_CHAR (date)

TO_NCHAR (datetime)

--

--

--

--

--

--

--

--

从原始

RAWTOHEX

RAWTONHEX

--

--

--

--

--

TO_BLOB

--

--

从 ROWID

ROWIDTOCHAR

--

--

--

--

--

--

--

--

从长/长原始

--

--

--

--

--

--

TO_LOB

--

--

从 CLOB, NCLOB, BLOB

TO_CHAR

TO_NCHAR

--

--

--

--

--

TO_CLOB

TO_NCLOB

--

--

从 CLOB, NCLOB, BLOB

TO_CHAR

TO_NCHAR

--

--

--

--

--

TO_CLOB

TO_NCLOB

--

--

从 BINARY_FLOAT

TO_CHAR (char.)

TO_NCHAR (char.)

TO_NUMBER

--

--

--

--

--

TO_BINARY_FLOAT

TO_BINARY_DOUBLE

从 BINARY_DOUBLE

TO_CHAR (char.)

TO_NCHAR (char.)

TO_NUMBER

--

--

--

--

--

TO_BINARY_FLOAT

TO_BINARY_DOUBLE

数据转换的安全注意事项

当日期时间值转换为文本 (通过隐式转换或未指定格式模型的显式转换) 时, 格式模型由一个全球化会话参数定义。根据源数据类型的不同, 参数名为NLS_DATE_FORMAT、 NLS_TIMESTAMP_FORMATNLS_TIMESTAMP_TZ_FORMAT可以在客户端环境或ALTER SESSION语句中指定这些参数的值。

当没有显式格式模型的转换应用于与动态 SQL 语句的文本连接的 datetime 值时, 对会话参数的格式模型的依赖会对数据库安全性产生负面影响。动态 SQL 语句是指其文本在被传递到数据库以便执行之前从片段中串联起来的语句。动态 SQL 经常与内置的 pl/sql 包DBMS_SQL或与 pl/sql 语句EXECUTEIMMEDIATE关联, 但这些不是唯一可以作为参数传递动态构造 SQL 文本的位置。例如:

EXECUTE IMMEDIATE
'SELECT last_name FROM employees WHERE hire_date > ''' || start_date || '''';

其中start_date具有数据类型DATE.

在上面的示例中, start_date的值将使用会话参数NLS_DATE_FORMAT中指定的格式模型转换为文本。结果将连接到 SQL 文本中。datetime 格式模型可以简单地由括在双引号中的文本组成。因此, 任何可以显式设置会话的全球化参数的用户都可以决定上述转换产生的文本。如果 sql 语句由 PL/SQL 过程执行, 则该过程容易受到 SQL 注入通过会话参数的攻击。如果过程使用定义者的权限运行, 且权限比会话本身高, 则用户可以获得对敏感数据的未经授权的访问。

注意:

此安全风险还适用于从数据库转换为文本的日期时间值构造 SQL 文本的中间层应用程序, 或通过保监日期时间函数。 如果会话全球化参数是从用户首选项获取的, 则这些应用程序是易受攻击的。

数值的隐式和显式转换也可能受到类似问题的影响, 因为转换结果可能取决于会话参数NLS_NUMERIC_CHARACTERS此参数定义十进制和组分隔符字符。如果将十进制分隔符定义为引号或双引号, 则会出现一些 SQL 注入的潜在可能性。


猜你喜欢

转载自blog.csdn.net/huyingzuo/article/details/80299563