我正在使用Oracle DB 11g
我有一个数据库表,主键是CHAR(4) -尽管只有数字用于该列。
我注意到有一些记录,例如显示'0018'或'0123'。
我注意到一些奇怪的事情,需要一些帮助
- CHAR列是否"自动"把0加到一个值上?
-我也注意到,当写一个SQL,如果我不使用引号在我的where子句,它返回结果,但如果我使用引号它不?例如
DB CHAR(4)列的键为'0018'
我使用这个查询
SELECT * FROM TABLE_A WHERE COLUMN_1=18;
我得到了预期的行。
但是当我尝试下面的
SELECT * FROM TABLE_A WHERE COLUMN_1='18';
这个不工作,但这个可以再次工作
SELECT * FROM TABLE_A WHERE COLUMN_1='0018';
所以我有点困惑如何第一个查询可以工作如预期没有引号?
CHAR列是否"自动";把0加到一个值上?
。来自文档:
如果插入的值小于列长度,Oracle会将该值空填充为列长度。
因此,如果您插入数字18
,它将隐式转换为字符串'18 '
,后面有两个空格。您可以在这个小提琴中看到这一点,它也显示了比较。
这意味着其他的东西是零填充你的数据-要么是你的应用程序/代码插入之前,或可能在一个触发器。
我也注意到,当写一个SQL,如果我不使用引号在我的where子句,它返回的结果,但如果我使用引号它不
数据类型比较和转换规则也在文档中显示:
当比较字符值和数值时,Oracle将字符数据转换为数值。
当你这样做的时候:
SELECT * FROM TABLE_A WHERE COLUMN_1=18;
字符串'0018'
隐式地转换为数字18
,以便它可以与您的数字文字进行比较。转换后,前导零是没有意义的,因此'0018'
,'018 '
和18
'都将匹配。
与您的零填充列值匹配,您确实得到一个结果:18
('0018'
转换为数字)=18
这意味着表中的每个值在进行比较之前必须进行转换;这也意味着如果你在column_1
上有一个正常的索引,那么它就不会在比较中使用。
当你这样做的时候:
SELECT * FROM TABLE_A WHERE COLUMN_1='18';
列和文字是相同的数据类型,因此不需要应用转换(因此可以使用普通索引)。Oracle将在这里使用空白填充比较语义,因为列是char
,将较短的文字值填充到列大小为'18 '
,然后只有在字符串完全匹配时才会匹配-所以'18 '
会匹配,但'0018'
或' 18 '
或其他任何东西都不会匹配。
与您的零填充列值不匹配,您没有得到结果:'0018'
!='18 '
('18'
填充到长度4)
当你这样做的时候:
SELECT * FROM TABLE_A WHERE COLUMN_1='0018';
列和字面值是相同的数据类型,所以没有转换,没有填充应用,因为字面值已经与列值相同的长度,并且它只会在字符串完全匹配时匹配-所以'0018'
会匹配,但'18 '
或' 18 '
或其他任何东西都不会匹配。
与您的零填充列值匹配,您确实得到一个结果:'0018'
='0018'
CHAR列是否"自动";把0加到一个值上?
不总是0,有时是空格。如果所有字符值都是数字,则将在字符字段的固定大小之前填充零。
所以我有点困惑如何第一个查询可以工作如预期没有引号?
由于隐式类型转换。系统将char转换为数字或将数字转换为char,在这种情况下,它要么去掉前导零并比较数字值,要么填充为相同的数据类型,然后进行比较。我很确定它将字符转换为数字,因此在比较时将前导零删除。
参见:https://docs.oracle.com/cd/B13789_01/server.101/b10759/sql_elements002.htm获取更多关于数据类型比较和隐式强制转换的详细信息
:
- in the case: SELECT * FROM TABLE_A WHERE COLUMN_1='18';我认为18已经是一个字符数据,所以它变成了'18 '(注意18后面有2个空格)与'0018'相比
- select * from table_a where column_1 =18;columN_1被强制转换为数字,所以18=18
- select * from table_a where column_1 ='0018';column_1已经是一个char(4),所以'0018' = '0018'