5

これは、T-SQL に基づくStack Exchange Data Explorerで遊んでいるときに繰り返し遭遇した問題です。

他の文字列の部分文字列として出現する場合を除いて、文字列を検索する方法は?

たとえばMyTable、列MyColに stringが含まれるテーブル内のすべてのレコードを選択し、stringの一部である s をfoo無視するにはどうすればよいでしょうか?foofoobar

迅速で汚い試みは次のようになります。

SELECT * 
FROM MyTable 
WHERE MyCol LIKE '%foo%' 
  AND MyCol NOT LIKE '%foobar%'

しかし、明らかにこれは一致しません。たとえばMyCol = 'not all foos are foobars'、私は一致させたいと思っています。

私が思いついた 1 つの解決策は、次のように、すべての出現箇所をfoobarダミー マーカー (の部分文字列ではないfoo) に置き換えてから、残りfooの sをチェックすることです。

SELECT * 
FROM MyTable 
WHERE REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%'

REPLACE()これは機能しますが、テーブル内のすべてのレコードに対して実行する必要があるため、あまり効率的ではないと思います。(SEDE の場合、これは通常、Posts現在約 3,000 万行あるテーブルになります。)これを行うためのより良い方法はありますか?

(FWIW、この質問を促した実際のユースケースhttp://は、スキームプレフィックスを使用するがホストを指していない画像 URL を持つ SO 投稿を検索することでしたi.stack.imgur.com。)

4

4 に答える 4

5

これまでに示した方法はいずれも、宣伝どおりに機能することが保証されておらずREPLACE、行のサブセットに対してのみ実行されます。

SQL Serverは、述語の短絡を保証せず、計算スカラーを派生テーブルと CTE の基礎となるクエリに移動できます

(ほとんど)動作が保証されている唯一のものはCASEステートメントです。IIF以下では、次のように展開される構文上の砂糖の種類を使用します。CASE

SELECT *
FROM   MyTable
WHERE  1 = IIF(MyCol LIKE '%foo%', 
               IIF(REPLACE(MyCol, 'foobar', 'X') LIKE '%foo%', 1, 0), 
               0);
于 2016-02-01T20:28:56.543 に答える
1

3 段階のフィルターが機能するはずです。

  1. '%foo%' に一致するすべての行を収集します。

  2. 'foobar' のすべてのインスタンスを出現しない文字列 (おそらく '' など) に置き換えます。

  3. 一致する '%foo%' をもう一度確認してください

ここでは、すべての行ではなく、潜在的に一致する行に対してのみ REPLACE を実行します。一致する割合が少ないと予想される場合、これははるかに効率的です。

SQL は次のようになります。

;with data as (
    select * 
    from MyTable 
    where MyCol like '%foo%'      
)
select *
from data
where replace(MyCol, 'foobar', 'X') like '%foo%'

SQL には式のショートカットがないため、サブクエリが必要であることに注意してください。エンジンは、単一のクエリ レベル内で効率的に処理するために、必要に応じてブール条件を自由に並べ替えることができます。

于 2016-02-01T11:58:16.183 に答える
0

foo周囲にスペースがあるのインスタンスを見つけることのみに関心があると仮定すると、

 SELECT * 
 FROM MyTable 
 WHERE MyCol LIKE 'foo %' OR MyCol LIKE '% foo %' OR MyCol LIKE '% foo'
于 2016-02-01T11:58:30.170 に答える