17440


例として掲示板システムで"コメント"テーブルから新規10件を表示、  
但し"NGワード"テーブル(1レコード1NGワードを保持)にあるNGワードが含まれるコメントは  
除外したい、というケースを想定して下さい。

NGワードは複数あります。  
このようなケースでなるべくコストの少ない検索方法を模索しているのですが  
何か良い方法は無いでしょうか。

追加：可能であればNGなコメントも取得自体はしておいてNGであるという状態を持ちたいです。  
となるとNGワードテーブルを結合してそのIDがNULLかどうか、という方法しか無さそうですが・・


CC BY-SA 3.0
2015-10-08T13:34:12.793
17431
2015-10-09T21:58:43.653
2015-10-08T16:51:09.393
11050
11050
question
mysql
DBから抽出したレコードを指定キーワード(複数)で絞り込むロジックについて


「なるべくコストが少ない検索方法」とのことですが、用途的にRDBMSがあまり得意としない処理のような気がします。  
とりあえずこんな感じで実装して、パフォーマンスが怪しくなってきたときに全文検索エンジンの導入等を検討してみるのはどうでしょうか。

### DATA

[code]

    create table blogs (
      title varchar(100),
      content text
      );
    
    create table ng_words (
      word varchar(100)
      );
    
    insert into blogs values ('blog1', 'Lorem ipsum dolor sit amet, vix in tantas officiis, pro.');
    insert into blogs values ('blog2', 'Lorem ipsum dolor sit amet, veri scripserit adversarium in vix.');
    insert into blogs values ('blog3', 'Lorem ipsum dolor sit amet, ad virtute sententiae neglegentur vel.');
    insert into blogs values ('blog4', 'Lorem ipsum dolor sit amet, ad sea nisl aliquip deseruisse.');
    insert into blogs values ('blog5', 'Lorem ipsum dolor sit amet, quo elitr aperiri tractatos id.');
    insert into blogs values ('blog6', 'Lorem ipsum dolor sit amet, alienum insolens eleifend id has.');
    
    insert into ng_words values ('vel'); -- remove blog3
    insert into ng_words values ('quo'); -- remove blog5
    
[/code]

### SQL

[code]

    SELECT b.* 
    FROM   blogs b 
    WHERE  NOT EXISTS(SELECT * 
                      FROM   ng_words n 
                      WHERE  b.content LIKE Concat('%', n.word, '%')) 
    ORDER  BY b.title 
    LIMIT  3 
    
[/code]

### RESULT

[![画像の説明をここに入力](https://i.stack.imgur.com/q90uS.png)](https://i.stack.imgur.com/q90uS.png)

なお、このコードの実行結果はこちらで確認できます。

<http://sqlfiddle.com/#!9/7dea4/4>

## 追記

unarist さんのコメントを受けて作った、LIKEではなくPOSITIONを使うバージョンです。  
POSITIONを使うと、 % のような「LIKEで特殊な意味を持つ文字」も検索できるようになります。

### DATA

[code]

    create table blogs (
      title varchar(100),
      content text
      );
    
    create table ng_words (
      word varchar(100)
      );
    
    insert into blogs values ('blog1', 'Lorem ipsum dolor sit amet, vix in tantas officiis, pro.');
    insert into blogs values ('blog2', 'Lorem ipsum dolor sit amet, veri scripserit adversarium in vix.');
    insert into blogs values ('blog3', 'Lorem ipsum dolor sit amet, ad virtute sententiae neglegentur %vel.');
    insert into blogs values ('blog4', 'Lorem ipsum dolor sit amet, ad sea nisl aliquip deseruisse.');
    insert into blogs values ('blog5', 'Lorem ipsum dolor sit amet, %quo elitr aperiri tractatos id.');
    insert into blogs values ('blog6', 'Lorem ipsum dolor sit amet, alienum insolens eleifend id has.');
    
    insert into ng_words values ('%v'); -- remove blog3
    insert into ng_words values ('quo'); -- remove blog5
    
[/code]

### SQL

[code]

    SELECT b.* 
    FROM   blogs b 
    WHERE  NOT EXISTS(SELECT * 
                      FROM   ng_words n 
                      WHERE  POSITION(n.word IN b.content) != 0) 
    ORDER  BY b.title 
    LIMIT  3 
    
[/code]

### RESULT

[![画像の説明をここに入力](https://i.stack.imgur.com/q90uS.png)](https://i.stack.imgur.com/q90uS.png)

### コード

<http://sqlfiddle.com/#!9/f0891/1>

### LIKEを使った場合のRESULT

[![画像の説明をここに入力](https://i.stack.imgur.com/RLdoX.png)](https://i.stack.imgur.com/RLdoX.png)

### LIKEの場合のコード

<http://sqlfiddle.com/#!9/f0891/3>


CC BY-SA 3.0
2015-10-08T23:14:53.020
17440
2015-10-09T21:58:43.653
2015-10-09T21:58:43.653
85
85
17431
answer