QA@IT

Oracle11gのユーザー関数で返却するCHARについて

4901 PV

ユーザー関数が返却するCHARでは、正しく比較できないケースがあります。

以下のようなパッケージ(仕様部は割愛)で、CHARを返却するfugaファンクションと、CHAR(20)で宣言したaValueを比較してみます。

create or replace PACKAGE BODY test AS

  PROCEDURE hoge
  IS
    aValue CHAR(20) := 'aValue';
    aResult CHAR(50);
  BEGIN    
    IF aValue = fuga() THEN
      DBMS_OUTPUT.PUT_LINE('result1:aValue equals fuga()');
    END IF;

    BEGIN
      SELECT 'aValue equals fuga()'
      INTO aResult
      FROM dual
      WHERE aValue = fuga();      
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
       aResult := 'aValue not equals fuga()';
    END;

    DBMS_OUTPUT.PUT_LINE('result2:' || aResult);    
  END;

  FUNCTION fuga
  RETURN CHAR
  IS
  BEGIN
    RETURN 'aValue';
  END;

END test;

hogeプロシージャをOracle11gで実行させた場合、結果は以下のようになります。

result1:aValue equals fuga()
result2:aValue not equals fuga()

IF文ではaValue = fuga()と判定されるのに、where句ではaValue != fuga()と判定されるのです。

where句の条件をrtrim(aValue) = fuga()とすれば、期待する結果が得られることから、空白埋めセマンティクスが発生していないことが原因だと思いますが、この振る舞いの違いは何に起因しているのでしょうか?

回答

原因はわかりませんが

http://docs.oracle.com/cd/E16338_01/server.112/b56299/sql_elements002.htm#sthref311

この規則では、2つの値の後続空白数のみが異なる場合、その2つの値は等しいとみなされます。Oracleでは、比較する両方の値が、CHARデータ型、NCHARデータ型、テキスト・リテラルのいずれかの式の場合、または USERファンクションの戻り値の場合 のみ空白埋め比較セマンティクスを使用します。

とありますので、等しいとみなされてほしい気はしますね。

訳文だと「または」の位置が若干曖昧ですので一応原文。

http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements002.htm#SQLRF51040

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 data type CHAR, NCHAR, text literals, or values returned by the USER function.

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。