SQLクエリのselect部分のスカラー関数は、where句のすべての条件を満たす行にのみ適用されると常に素朴に想定していたと思います。
今日、私はベンダーからのコードをデバッグしていて、その仮定に異議を唱えました。このコードが失敗したと私が考えることができる唯一の理由は、WHERE句によってフィルターで除外されるべきデータに対してSubstring()関数が呼び出されていることです。しかし、フィルタリングが行われる前に部分文字列呼び出しが適用されているようで、クエリは失敗しています。これが私の言いたいことの例です。2つのテーブルがあり、それぞれに2つの列があり、それぞれ2つの行と1つの行があるとします。それぞれの最初の列は単なるIDです。NAMEは単なる文字列であり、NAME_LENGTHは、同じIDを持つ名前の文字数を示します。LONG_NAMESテーブルに対応する行があるのは、複数の文字を含む名前のみであることに注意してください。
NAMES: ID, NAME
1, "Peter"
2, "X"
LONG_NAMES: ID, NAME_LENGTH
1, 5
最後の3文字を切り取って各名前を出力するクエリが必要な場合は、最初に次のようなものを試してみてください(今のところSQL Serverの構文を想定しています)。
SELECT substring(NAME,1,len(NAME)-3)
FROM NAMES;
「X」に達すると、部分文字列呼び出しで負の数を使用しようとし、失敗するため、これでエラーが発生することがすぐにわかります。私のベンダーがこれを解決することを決定した方法は、文字列が短すぎてlen-3クエリが機能しない行を除外することでした。彼は別のテーブルに参加することによってそれをしました:
SELECT substring(NAMES.NAME,1,len(NAMES.NAME)-3)
FROM NAMES
INNER JOIN LONG_NAMES
ON NAMES.ID = LONG_NAMES.ID;
一見すると、このクエリは機能するように見えます。結合条件は、部分文字列呼び出しが失敗するのに十分短いNAMEフィールドを持つ行をすべて削除します。
ただし、私が観察できることから、SQL Serverは、テーブル内のすべての部分文字列式を計算し、結合を適用して行を除外しようとすることがあります。これはこのように起こるはずですか?特定のことがいつ発生するかを知ることができる、文書化された操作の順序はありますか?特定のデータベースエンジンまたはSQL標準の一部に固有ですか?NAMESテーブルに述語を含めて短い名前(len(NAME)> 3など)を除外することにした場合、SQL Serverは、部分文字列を適用しようとした後にそれを適用することも選択できますか?もしそうなら、部分文字列を実行する唯一の安全な方法は、selectの「casewhen」構文でそれをラップすることだと思われますか?