15

2つのテーブルを結合するクエリがあります。1つのテーブルにはvarchar型の列があり、もう1つのテーブルにはnumber型の列があります。3つのOracleデータベースでクエリを実行しましたが、説明できると思いますが、奇妙な結果がいくつか見られます。2つのデータベースでは、次のようなものが機能します。

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=a.col1;

このクエリでは、tableA.col1はタイプnumberであり、tableB.col2はタイプvarcharです。これは、2つのデータベースでは正常に機能しますが、3番目のデータベースでは機能しません。3番目に(ORA-01722)エラーが発生します。3番目に私は次のようなことをする必要があります...

select a.col1, b.somecol 
from tableA a inner join tableB b on b.col2=to_char(a.col1);

これはすべてのデータベースで機能します。私が持っている質問はなぜですか?上記は単純化されたクエリであり、実際のクエリはもう少し複雑で多くのデータを取得するため、最初のバージョンの方がはるかに高速です。それをすべての環境で機能させることができれば、それは素晴らしいことです。

これが一部のOracleデータベースで機能し、データ型にキャストされていない他のデータベースでは機能しない理由を誰かが知っていますか?そのような動作を可能にするグローバル設定はありますか?

4

1 に答える 1

22

暗黙的な変換が失敗する理由の1つは、結合するvarchar列に数値ではないデータが含まれている場合です。Oracleは、文字列を変換することによって数値をvarchar2結合に処理するため(Garyのコメントの引用を確認してください)、実際にこれを実行します。

select a.col1, b.somecol 
from tableA a inner join tableB b on to_number(b.col2)=a.col1;

tableB.col2に数値ではない値が含まれている場合(可能性が非常に高いと思われますが、結局は文字列です)、それはhurlしますORA-01722: invalid number。数値列を文字列に明示的にキャストすることにより、Oracleのデフォルトの動作を短絡させます。

最初の2つの環境でこの問題が発生しないという事実は、構成ではなく運の問題です。クエリを中断するのに必要な非数値文字列は1つだけなので、いつでも攻撃される可能性があります。したがって、実際には、すべての環境で明示的な変換を使用して実行する必要があります。

パフォーマンスに関しては、関数ベースのインデックスを作成できます...

create index whatever_idx on tableA ( to_char(col1) )
/ 
于 2010-02-24T23:38:29.173 に答える