当我们在oracle

时间:2017-11-16 05:35:17

标签: sql oracle

在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'

enter image description here

2 个答案:

答案 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)) 列,则保留输入的原始空格/宽度,并且字符串的逻辑比较符合您的预期。

Demo

答案 1 :(得分:2)

查看literals上的Oracle文档:

  

文本文字具有CHARVARCHAR2数据类型的属性:

     
      
  • 在表达式和条件中,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() function表示:

  

如果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,并且没有使用空白填充的比较语义,并且相等性不正确。