SQLite WHERE 列 MATCH 参数绑定

SQLite WHERE column MATCH parameter binding

我有 FTS table 和匹配列包含 "all" 和 "in" 的所有行的查询。

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

我怎样才能使它与参数绑定一起工作?所以我可以提供:

values: ["all", "in"]

SQLite 使用纯字符串作为全文模式。因此,您必须从 多个 单词构建自己的 one 全文模式字符串,并将其作为一个 FMDB 参数提供,如下所示。

let words = ["all", "in"]
let pattern = words
    .map { "\"\([=10=])\"" } // 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