天天看點

OCCI處理CHAR類型字元串變量的不同

問題背景:

一個舊應用,原先應用是用proc寫的,9i的庫,現在應用需要改為使用OCCI,其中有一段查詢邏輯:select ... where upper(state)=upper(:1)。

(此處請不要糾結于where條件中state字段使用了upper函數,因為此表資料量很小,且其曆史比較悠久,未建索引。)

對應表中定義的state字段類型是char(3),但此處查詢條件變量的值可能是兩位,例如'NY'。

現象:

1. 使用sqlplus執行select ... where upper(state)=upper(:1)可以正常顯示。

2. 使用sql developer執行select ... where upper(state)=upper(:1)可以正常顯示。

3. 使用proc執行,可以正常顯示。

4. 使用OCCI方式,執行,顯示為空。

解決:

對于使用OCCI的方式,将其改寫為:

1. select ... where trim(upper(state)) = trim(upper(:1));

2. select ... where upper(state) = upper(rpad(:1, 3, ' '));

原理推斷:

1. 首先char和varchar2類型的最大差別,就是char是定長類型,varchar2是不定長類型,網上包括官方文檔有很多介紹了,用例子簡單講,就是:

create table test(

a char(25),

b varchar2(25)

);

insert into test values('a', b');

a字段存儲的是“a+24個空格”,b字段存儲的就是“b”。

可以從select a, length(a), b, length(b) from test;進一步驗證。

即char會占用最大的存儲空間,varchar2則隻會存儲實際占用的空間。

雖然翻了OCCI的文檔,并未找到對這個問題的解釋,但從Oracle官方文檔對填補空格比較字元串的語義說明,可以看出一些端倪:

Blank-Padded Comparison Semantics

If the two values have different lengths, then Oracle first adds blanks to the end of the shorter one so their lengths are equal. Oracle then compares the values character by character up to the first character

that differs. The value with the greater character in the first differing position is considered greater.

If two values have no differing characters, then they are considered equal. This rule means that two values are equal if they differ only in the number of trailing blanks. Oracle uses blank-padded comparison semantics only when both values in the comparison

are either expressions of datatype CHAR, NCHAR, text literals, or values returned by the USER function.

Nonpadded Comparison Semantics

Oracle compares two values character by character up to the first character that differs. The value with the greater character in that position is considered greater. If two values of different length are identical up to the end of the shorter one, then the

longer value is considered greater. If two values of equal length have no differing characters, then the values are considered equal. Oracle uses nonpadded comparison semantics whenever one or both values in the comparison have the datatype VARCHAR2 or NVARCHAR2.

即對于CHAR、NCHAR類型的字元串比較,Oracle首先會自動補齊空格,然後再一個字元一個字元地比較,不會因為空格數不同認為兩者不同,且這個過程應該不是簡單的trim()操作,因為如果字段有索引仍會使用。

對于VARCHAR2、NVARCHAR2類型的字元串比較,由于其不會自動存儲空格,如果有空格,則也是作為有意義的存儲,是以不存在上述問題。

綜上所述,對于CHAR類型,不應該因為補空格位數的問題,作為比較的依據,除非使用的where

a = trim('a'),人為對值進行處理,是以有理由懷疑OCCI對CHAR類型字元串的比較,至少和其他終端查詢的邏輯不同,至于是不是bug,需要看看有沒有官方的解釋了。