在Oracle中,我看到,某个时间'A ' = 'A'
,但有时'A ' != 'A'
,请参阅下面的示例,您将看到详细信息。我一直试图缩短代码。
CREATE TABLE AAA (
T1 CHAR(3),
T2 VARCHAR(3),
T3 VARCHAR(5)
);
insert into AAA
SELECT 'A','A ', 'A ' FROM DUAL;
COMMIT;
SELECT * FROM AAA WHERE T1 = 'A'
UNION ALL
SELECT * FROM AAA WHERE T2 = 'A '
UNION ALL
SELECT * FROM AAA WHERE T2 = 'A '
UNION ALL
SELECT * FROM AAA WHERE TRIM(T2) = TRIM('A ')
UNION ALL
SELECT CASE WHEN 'A' = 'A ' THEN '1' ELSE '0' END T1,
CASE WHEN 'A ' = 'A' THEN '1' ELSE '0' END T2,
CASE WHEN 'A ' = 'A ' THEN '1' ELSE '0' END T2
FROM DUAL;
我问这个问题,因为在我的数据库中,当我将表A连接到表B时,我们TRIM(A.ID)= TRIM(B.REFID),有时我们不需要这样做。当我们需要TRIM(列)?什么时候'A ' = 'A'
?何时'A ' != 'A'
?
答案 0 :(得分:2)
我认为在查询实际表时您所看到的行为是预期的,并且唯一可能让您感到惊讶的行为是在以下查询中:
SELECT CASE WHEN 'A' = 'A ' THEN '1' ELSE '0' END T1,
CASE WHEN 'A ' = 'A' THEN '1' ELSE '0' END T2,
CASE WHEN 'A ' = 'A ' THEN '1' ELSE '0' END T2
FROM DUAL;
从this Oracle discussion开始,似乎正在发生的事情与'A'
,'A '
等有char
类型而不是 varchar2
种类型。因此,为了比较两个char
值,它们需要具有相同的长度。请考虑以下CASE
表达式:
CASE WHEN 'A ' = 'A' THEN '1' ELSE '0' END T2
此处,'A'
文字(char(1)
)将通过右边的空格填充来提升为char(8)
。因此,当比较实际发生时,LHS和RHS实际上是相同的。请注意,以下CASE
表达式不会评估为真实条件:
CASE WHEN ' A' = 'A' THEN '1' ELSE '0' END T2
这是因为填充会发生在右侧的'A'
,因此' A'
会与'A '
进行比较,而varchar
则不同。
按照以下链接进行演示,该演示显示如果您使用所有SELECT a.*, b.*
FROM table1 a
INNER JOIN table2 b
ON (a.name = b.name AND (a.d1>0 AND a.d2>0 AND a.d3>0 AND a.d4>0 AND a.d5>0) AND (b.c1>0 AND b.c2>0 AND b.c3>0 AND b.c4>0 AND b.c5>0))
列,则保留输入的原始空格/宽度,并且字符串的逻辑比较符合您的预期。
答案 1 :(得分:2)
查看literals上的Oracle文档:
文本文字具有
CHAR
和VARCHAR2
数据类型的属性:
- 在表达式和条件中,Oracle通过使用空白填充的比较语义来比较文本文字,就好像它们具有数据类型
CHAR
一样。
以及blank-padded comparison semantics州的文档:
使用空白填充语义,如果两个值具有不同的长度,则Oracle首先将空白添加到较短值的末尾,因此它们的长度相等。然后,Oracle将逐个字符的值与不同的第一个字符进行比较。在第一个不同位置具有较大字符的值被认为更大。如果两个值没有不同的字符,那么它们被认为是相等的。此规则意味着如果两个值仅在尾随空白的数量上不同,则它们是相等的。仅当比较中的两个值都是数据类型
CHAR
,NCHAR
,文本文字或值的表达式时,Oracle才使用空白填充比较语义由USER
函数返回。
所以,对于你的例子:
SELECT * FROM AAA WHERE T1 = 'A'
由于比较的左侧T1
等于'A '
,因此CHAR(3)
,右侧是文字文字'A'
,然后空白使用了-padded比较语义,'A ' = 'A'
为真。
然后:
SELECT * FROM AAA WHERE T2 = 'A '
比较的左侧T2
等于'A '
,VARCHAR2(3)
,右侧是文字文字'A '
,然后空白 - 不使用填充比较语义(双方都不是CHAR
或文本文字)但值相等('A ' = 'A '
)所以条件为真。
和
SELECT * FROM AAA WHERE T2 = 'A '
LHS是VARCHAR2
等于'A '
,RHS是等于'A '
的文字文字;将不使用空白填充的比较语义,并且值不相等,因此条件不为真,并且不会返回该行。
然后:
SELECT * FROM AAA WHERE TRIM(T2) = TRIM('A ')
如果trim_source是字符数据类型,则返回的字符串为
VARCHAR2
数据类型;如果trim_source为LOB
数据类型,则返回LOB
。
两个值都被修剪,因此您具有条件'A' = 'A'
,其中两边都是VARCAHR2
数据类型,因此不会使用空白填充的比较语义,但值相等,因此条件为真,该行将被退回。
最后:
SELECT CASE WHEN 'A' = 'A ' THEN '1' ELSE '0' END T1,
CASE WHEN 'A ' = 'A' THEN '1' ELSE '0' END T2,
CASE WHEN 'A ' = 'A ' THEN '1' ELSE '0' END T2
FROM DUAL;
在所有情况下,相等的两边都是文本文字,因此将使用空白填充的比较语义,以便
'A' = 'A '
LHS将被填充,因此字符串的长度相同; 'A ' = 'A'
RHS将被填充; 'A ' = 'A '
两边长度相等,因此不需要填充。在每种情况下,平等是相等的。
如果您使用CAST
将文字文字更改为VARCHAR2
数据类型:
SELECT CASE WHEN 'A' = CAST( 'A ' AS VARCHAR2(5) ) THEN 1 ELSE 0 END AS T1
FROM DUAL
LHS是一个文本文字,但RHS是VARCHAR2
,并且没有使用空白填充的比较语义,并且相等性不正确。