2017-10-19 2 views
1

カラムに "all"と "in"の両方が含まれているすべての行に一致するFTSテーブルとクエリがあります。SQLiteのWHERE列のMATCHパラメータバインド

try db.executeQuery("SELECT * FROM table WHERE column MATCH '\"all\" AND \"in\"'", values: nil) 

パラメータ結合でこの作業を行うにはどうすればよいですか?だから私は提供することができます:

values: ["all", "in"] 

答えて

4

SQLiteはフルテキストパターンとして平文文字列を使用します。したがって、フルテキストパターン文字列を複数のワードから構築し、以下のように1つのFMDBパラメータとして提供する必要があります。

let words = ["all", "in"] 
let pattern = words 
    .map { "\"\($0)\"" } // wrap each word inside quotes 
    .joined(separator: " AND ") 
try db.executeQuery("SELECT * FROM table WHERE column MATCH ?", values: [pattern]) 

すべてのパターンが有効ではないことに注意してください。 Full-Text Index Queries Grammarを参照してください。これは、一部の入力がSQLiteエラーを引き起こすことを意味します。たとえば、単語がテキストフィールドから来て、ユーザが"attackのように引用符を入力した場合、無効なパターン""attack"を作成して、SQLiteが解析しないようにすることができます(SQLiteエラー1:malformed MATCH expression)。

あなた自身でユーザー入力をサニタイズすることはできますが、使用可能な最大限の情報を保持しながらこれを行うことは困難です。結局のところ、アプリケーションユーザは通常、SQLiteの微妙なことに気づいていません。面白い検索文字列を入力すると空の検索結果が表示されることはありません。

パターンサニタイズを実行する必要がある場合は、フルテキスト検索を大いにサポートしているFMDBの代わりにGRDBを使用することをおすすめします。ときに、ユーザーの種類"attackFTS3Pattern(matchingAllTokensIn:)ではなく、失敗の正気attack FTSパターンを建設する

let userInput = textField.text 
let pattern = FTS3Pattern(matchingAllTokensIn: userInput) 
let rows = try Row.fetchAll(db, "SELECT * FROM table WHERE column MATCH ?", arguments: [pattern]) 

:これは、ユーザーの入力から安全なパターンを構築することができます。 GRDBはSQLite自体を使用して墨塗りを実行します。つまり、かなり堅牢です。

詳細については、GRDB full-text search documentationを参照してください。

+0

非常に詳細で偉大な答えをありがとう!間違いなくGRDBをチェックします(ほとんどの面でFMDBの改善のようです)。 – Kirsteins

+0

ありがとう! GRDBはFMDBの改善です、そうです。革命ではない。アプリケーションのリファクタリングを大幅に削減することなく、FMDBからGRDBに簡単に移行できます。しかし、SQLレベルのレイヤーの上には、必要に応じて最終的に使用する概念が追加されています。漸進的な開示FTW! –

+0

'FTS3Pattern(matchingAllTokensIn:" all in ")'は 'all in'の生パターンを返します。 'すべてAND''を返してはいけませんか? – Kirsteins