簡単な答えは次のとおりです。はい、引用を修正すると、2つは同じ結果になるはずです。パーセント記号は、他の文字と同様に、準備されたステートメントから「取り除かれ」ません。
より長い答え: 準備されたステートメントと使い捨てステートメントの問題は複雑になる可能性があります。1 回だけ実行する場合、データベース エンジンが準備済みステートメントのすべてのセットアップを実行し、値を挿入し、エンジンが決定するまでキャッシュに保持する必要があるため、準備済みステートメントに時間がかかります。それをフラッシュします。また、オプティマイザーは準備済みステートメントを効率的に処理できないことがよくあります。プリペアド ステートメントの要点は、オプティマイザーがクエリを解析し、クエリ プランを 1 回考案することです。「customer_type=? および customer_zip=? の顧客から customer_name を選択」のようなことを言うとします。タイプとジップの両方にインデックスがあります。使い捨てのステートメント (もちろん、疑問符ではなく実際の値が入力されています) を使用すると、多くのデータベース エンジンのクエリ オプティマイザは、2 つのフィールドの値の分布に関する統計を調べ、より小さなレコード セットを提供するインデックスを選択し、これらすべてを順番に読み取り、2 番目のテストに失敗したレコードを除外します。準備されたステートメントでは、提供される値を知る前にインデックスを選択する必要があるため、効率の低いインデックスを選択する可能性があります。
未知の値を引用符で囲み、それを SQL ステートメントに詰め込むだけのコードを絶対に書いてはいけません。準備済みステートメントを使用するか、埋め込まれた引用符を適切にエスケープする関数を作成してください。このような関数を書くのは簡単です。JDBC に含まれていない理由がわからないので、自分で作成してすべてのアプリに含める必要があります。(一部の SQL ダイアレクトには、エスケープする必要がある単一引用符以外の文字がある場合、これは特に当てはまります。)
Java でのこのような関数の例を次に示します。
public static String q(String s)
{
if (s==null)
return "null";
if (s.indexOf('\'')<0)
return "'"+s+"'";
int sl=s.length();
char[] c2=new char[sl*2+2];
c2[0]='\'';
int p2=1;
for (int p=0;p<sl;++p)
{
char c=s.charAt(p);
if (c=='\'')
c2[p2++]=c;
c2[p2++]=c;
}
c2[p2++]='\'';
return new String(c2,0,p2);
}
(注:コードから取り出したバージョンからその関数を編集して、ここでは関係のないいくつかの特別なケースを排除しました-それを行うときにいくつかの小さなエラーを導入した場合は申し訳ありません。)
通常、「q」のような非常に短い名前を付けるので、次のように書くことができます。
String sql="select customer_name from customer where customer_type="+q(custType)
+" and customer_zip="+q(custZip);
またはそのような迅速かつ簡単なもの。これは「関数に完全で意味のある名前を付ける」という違反ですが、同じ関数を 1 つのステートメントで 10 回使用する可能性があるここでは価値があると思います。
次に、オーバーロードして、日付、数値、およびその他の特殊な型を取得し、適切に処理します。