Oracle - 为什么 CHAR 列自动添加前导零?

rod*_*063 1 sql oracle char oracle11g oracle-sqldeveloper

我正在使用 Oracle DB 11g

我有一个数据库表,其主键是 CHAR(4) - 尽管该列仅使用数字。

我注意到有些记录显示“0018”或“0123”。

我注意到很少有奇怪的事情并且需要一些帮助

- CHAR 列是否“自动”将零填充到某个值?

-我还注意到,在编写 SQL 时,如果我不在 where 子句中使用引号,它会返回结果,但如果我使用引号,它不会返回结果?例如

DB CHAR(4) 列的键为“0018”

我用这个查询

SELECT * FROM TABLE_A WHERE COLUMN_1=18;
Run Code Online (Sandbox Code Playgroud)

我按预期得到了行。

但是当我尝试以下操作时

SELECT * FROM TABLE_A WHERE COLUMN_1='18';
Run Code Online (Sandbox Code Playgroud)

这不起作用,但它又起作用了

SELECT * FROM TABLE_A WHERE COLUMN_1='0018';
Run Code Online (Sandbox Code Playgroud)

所以我有点困惑第一个查询如何在没有引号的情况下按预期工作?

Ale*_*ole 5

CHAR 列是否“自动”将零填充到某个值?

否。来自文档

如果插入的值短于列长度,则 Oracle 会将该值空白填充到列长度。

因此,如果您插入数字,18它将隐式转换为字符串'18 ',并带有两个尾随空格。您可以在这个小提琴中看到这一点,它也显示了比较。

这意味着其他东西正在对您的数据进行零填充 - 要么是插入之前的应用程序/代码,要么可能是在触发器中。

我还注意到,在编写 SQL 时,如果我不在 where 子句中使用引号,它会返回结果,但如果我使用引号,它不会返回结果

数据类型比较和转换规则也在文档中显示:

当比较字符值和数值时,Oracle 会将字符数据转换为数值。

当你这样做时:

SELECT * FROM TABLE_A WHERE COLUMN_1=18;
Run Code Online (Sandbox Code Playgroud)

该字符串'0018'会隐式转换为数字18,以便可以将其与数字文字进行比较。一旦转换后,前导零就毫无意义,因此'0018','018 '18 ' 都会匹配。

使用匹配的零填充列值,您确实会得到结果:(18转换'0018'为数字)=18

这意味着表中的每个值都必须先进行转换才能进行比较;这也意味着,如果您有一个正常的索引,那么column_1它就不会用于该比较。

当你这样做时:

SELECT * FROM TABLE_A WHERE COLUMN_1='18';
Run Code Online (Sandbox Code Playgroud)

列和文字是相同的数据类型,因此无需应用转换(因此可以使用普通索引)。Oracle 将在这里使用空白填充比较语义,因为列是char,将较短的文字值填充为列大小'18 ',然后只有当字符串完全匹配时才会匹配 - 所以会匹配,'18 ''0018'' 18 '或其他任何东西都不会匹配。

如果零填充的列值不匹配,则不会得到结果:'0018'!= '18 ''18'填充到长度 4)

当你这样做时:

SELECT * FROM TABLE_A WHERE COLUMN_1='0018';
Run Code Online (Sandbox Code Playgroud)

列和文字是相同的数据类型,因此没有转换,没有应用填充,因为文字已经与列值的长度相同,并且只有在字符串完全匹配时它才会匹配 - 所以会'0018'匹配 but'18 '' 18 '或其他任何内容不会。

使用匹配的零填充列值,您确实会得到结果:'0018'='0018'