2017-10-19 6 views
1

J'ai une table FTS et une requête qui correspond à toutes les lignes où la colonne contient à la fois "all" et "in".SQLite WHERE colonne Liaison de paramètre MATCH

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

Comment puis-je faire en sorte que cela fonctionne avec la liaison de paramètres? Je peux donc fournir:

values: ["all", "in"] 

Répondre

4

SQLite utilise des chaînes simples comme modèles de texte intégral. Vous devez donc créer vous-même un chaîne de motif de texte intégral à partir de plusieurs mots, et fournissez-le comme un paramètre FMDB, comme ci-dessous.

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]) 

Attention, tous les motifs ne sont pas valides. Voir le Full-Text Index Queries Grammar. Cela signifie que certaines entrées vont déclencher des erreurs SQLite. Par exemple, si les mots proviennent d'un champ de texte et que l'utilisateur tape un devis, comme dans "attack, vous pouvez générer le modèle non valide ""attack" que SQLite n'analysera pas (erreur SQLite 1: malformed MATCH expression).

Vous pouvez essayer de désinfecter vous-même l'entrée de l'utilisateur, mais cela est difficile à faire tout en préservant le maximum d'informations utilisables. Après tout, les utilisateurs d'application ne sont généralement pas conscients des subtilités de SQLite: il est inutile de les punir avec des résultats de recherche vides s'ils tapent une chaîne de recherche amusante.

Si vous avez besoin d'effectuer un nettoyage de motifs, je vous recommande de consulter GRDB, une alternative à FMDB avec un grand support pour la recherche en texte intégral. Il peut construire des modèles de sécurité de l'entrée utilisateur:

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

Lorsque les types d'utilisateurs "attack, le FTS3Pattern(matchingAllTokensIn:) construiraient le modèle attack FTS sain d'esprit au lieu d'échouer. GRDB utilise SQLite lui-même pour effectuer la désinfection, ce qui signifie que c'est assez solide.

Pour plus d'informations, voir GRDB full-text search documentation.

+0

Merci pour la réponse très détaillée et excellente! Va certainement vérifier GRDB (ressemble à une amélioration pour la FMDB dans la plupart des aspects). – Kirsteins

+0

Merci! GRDB est une amélioration de la FMDB, vous avez raison. Pas une révolution. On peut facilement migrer de FMDB à GRDB sans refactoring lourd d'application. Pourtant, au-dessus de la couche SQL, GRDB ajoute des concepts que l'on peut éventuellement utiliser en cas de besoin. La divulgation progressive FTW! –

+0

'FTS3Pattern (matchingAllTokensIn:" all in ")' retourne le motif brut 'all in'. Ne devrait-il pas retourner 'all AND '? – Kirsteins