SQLDeveloper查询自动填充CHAR字段

SQLDeveloper query automatic padding CHAR field

鉴于 table ATABLE 的字段 AFIELD 类型为 CHAR(8),并且我有一个值为 "1234567 "[=16= 的字段]

为什么,在SQL开发者中,如果我查询:

SELECT * FROM ATABLE WHERE AFIELD = '1234567';

它会自动填充缺少的 space 和 return 结果,如果我用 :

查询
SELECT * FROM ATABLE WHERE AFIELD = :value;

并输入值,不会吗?

你是对的

SELECT * FROM ATABLE WHERE AFIELD = :value;

不能如您所愿地使用 CHAR。

无论如何,我注意到以下查询可以如您所愿地工作:

SELECT * FROM ATABLE WHERE AFIELD = &value;

如果你在多个地方使用&value,你可以在第一次使用&&value(双&)(在其他地方使用&value), 以避免多次输入相同的值; 当您必须更改该值时,您可以取消定义它:

undef value;

From the documentation:

Within expressions and conditions, Oracle treats text literals as though they have the data type CHAR by comparing them using blank-padded comparison semantics.

当您执行 WHERE AFIELD = '1234567' 时,文本文字 '1234567' 被视为 char 并且 blank-padded comparison semantics 用于比较列值和文字。即使文字没有尾随 space,这些语义将它们视为相同,因此它找到了匹配项。

当您使用绑定变量时,您分配给它的文字是 char,但绑定变量本身是 varchar2 - 即使您将其声明为 char,奇怪,尽管在那种情况下该值仍然是 blank-padded:

var char_value char(8);
exec :char_value := '1234567';
var varchar2_value varchar2(8);
exec :varchar2_value := '1234567';

select dump('1234567') as d1, dump(:char_value) as d2, dump(:varchar2_value) as d3
from dual;

D1                                   D2                                   D3                                  
------------------------------------ ------------------------------------ ------------------------------------
Typ=96 Len=7: 49,50,51,52,53,54,55   Typ=1 Len=8: 49,50,51,52,53,54,55,32 Typ=1 Len=7: 49,50,51,52,53,54,55   

文本文字是data type 96 (char),而两个绑定变量都是类型1(varchar/varchar2);但请注意 char_value 绑定变量有尾随 space,长度为 8,最后一个字符为代码点 32。

当您将 char 列值与 varchar2 绑定变量进行比较时,列值是 implicitly convertedcharvarchar2:

The following rules govern implicit data type conversions:

  • During SELECT FROM operations, Oracle converts the data from the column to the type of the target variable.

所以你的 space-padded char(8) 列值被隐式转换为 varchar2(8) 以匹配绑定变量的数据类型,然后因为它们是 varchar2 非填充比较语义被使用了。

当您将 char(8) 列与假定的 char(8) 绑定变量进行比较时,您实际上是在与填充的 varchar2(8) 进行比较 - 但隐式转换的列值和blank-padded 绑定变量其实是一样的,都是尾随space; '1234567 ''1234567 ' 相同,因此存在匹配,即使使用非填充比较语义也是如此。

使用 varchar2(8) 绑定变量会发生同样的事情,但现在绑定值 填充,并且因为您使用非填充比较语义来比较 '1234567 ''1234567' - 它们不相同,因此没有匹配项,查询没有返回任何数据。


正如@a_horse_with_no_name所说,你应该几乎总是使用varchar2而不是char。但是,如果您必须使用它并且坚持使用它,那么至少要确保您使用相同的数据类型进行比较。