Oracleを扱ったのはこれが初めてであり、このエラーを受け取った理由を理解するのに苦労しています。
OracleのODT.NET w/C#とクエリのwhere句で次のコードを使用しています。
WHERE table.Variable1 = :VarA
AND (:VarB IS NULL OR table.Variable2 LIKE '%' || :VarB || '%')
AND (:VarC IS NULL OR table.Variable3 LIKE :VarC || '%')
そして、私は次のようにパラメータ値を追加しています:
cmd.Parameters.Add("VarA", "24");
cmd.Parameters.Add("VarB", "test");
cmd.Parameters.Add("VarC", "1234");
このクエリを実行すると、サーバーは以下を返します。
ORA-01008: not all variables bound
「AND(....」行のいずれかをコメント化すると、クエリは正常に完了します。
3つのパラメーターではなく2つのパラメーターのみでクエリを実行している場合、なぜクエリが正常に実行されるのですか?私が受け取っているエラーは意味がありません
OracleのODP.Netプロバイダーは、デフォルトとして位置によるバインドを使用します。名前でバインドするように動作を変更します。プロパティ BindByName をtrueに設定します。パラメーターの二重定義を却下できるよりも。
using(OracleCommand cmd = con.CreateCommand()) {
...
cmd.BindByName = true;
...
}
一見簡単そうに思えますが、同じバインド変数を2回使用する場合は、2回設定する必要があると思います。
cmd.Parameters.Add("VarA", "24");
cmd.Parameters.Add("VarB", "test");
cmd.Parameters.Add("VarB", "test");
cmd.Parameters.Add("VarC", "1234");
cmd.Parameters.Add("VarC", "1234");
確かに、PL/SQLのネイティブダイナミックSQLにはそうです。
SQL> begin
2 execute immediate 'select * from emp where ename=:name and ename=:name'
3 using 'KING';
4 end;
5 /
begin
*
ERROR at line 1:
ORA-01008: not all variables bound
SQL> begin
2 execute immediate 'select * from emp where ename=:name and ename=:name'
3 using 'KING', 'KING';
4 end;
5 /
PL/SQL procedure successfully completed.
また、Sqlを
table.Variable2 LIKE '%' || :VarB || '%'
そして、クライアントにnullではなくVarBの任意の値に「%」を提供させます。ある意味では、これはもっと自然だと思います。
Sqlを次のように変更することもできます
table.Variable2 LIKE '%' || IfNull(:VarB, '%') || '%'