2017-10-19 135 views
1

我有FTS表和查询匹配列中包含“all”和“in”的所有行。SQLite WHERE列MATCH参数绑定

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

如何使这个参数绑定的工作?所以我可以提供:

values: ["all", "in"] 

回答

4

SQLite使用普通字符串作为全文模式。因此,您必须自行构建您自己的一个全文模式字符串多个字,并将其作为一个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),则可能会构建SQLite无法解析的无效模式""attack"(SQLite错误1:malformed MATCH expression)。

您可以尝试自己清理用户输入,但在保留最大可用信息的同时很难做到这一点。毕竟,应用程序用户通常不知道SQLite的细微之处:如果他们碰巧输入了一个有趣的搜索字符串,那么没有必要用空搜索结果惩罚他们。

如果您需要执行模式清理,我建议您查看一下GRDB,FMDB的替代方案,对全文搜索有很大的支持。它可以根据用户输入构建安全模式:

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

当用户键入"attack,该FTS3Pattern(matchingAllTokensIn:)将建立理智attack FTS模式,而不是失败的。 GRDB使用SQLite本身来执行清理,这意味着它非常稳定。请参阅GRDB full-text search documentation

+0

非常详细和很好的答案,谢谢!肯定会检查出GRDB(看起来像FMDB在大多数方面的改进)。 – Kirsteins

+0

谢谢! GRDB是FMDB的改进,你是对的。不是革命。人们可以轻松地从FMDB迁移到GRDB,而无需重复应用程序重构。然而,在SQL层的基础上,GRDB增加了在需要时最终可以使用的概念。逐步披露FTW! –

+0

'FTS3Pattern(matchingAllTokensIn:“all in”)''返回全部原始模式。它不应该返回'全部和在'? – Kirsteins