2016-08-13 69 views
3

我想使用SQLite.swift查询FTS表。 Previously I have done it in Android。什么我试图做的实质是this如何使用IN条件访问SQLite.swift中的FTS表

SELECT * 
FROM t2 
WHERE id IN (SELECT docid 
      FROM fts_table 
      WHERE col_text MATCH 'something') 

SQLite.swift documentation我看到IN condition可以这样写this

users.filter([1, 2, 3, 4, 5].contains(id)) 
// SELECT * FROM "users" WHERE ("id" IN (1, 2, 3, 4, 5)) 

和虚拟表可以查询像this

let wonderfulEmails = emails.match("wonder*") 
// SELECT * FROM "emails" WHERE "emails" MATCH 'wonder*' 

let replies = emails.filter(subject.match("Re:*")) 
// SELECT * FROM "emails" WHERE "subject" MATCH 'Re:*' 

但是,我不知道如何结合这些。我真的不想要execute arbitrary SQL(尽管这现在工作得益于this answer的帮助)。

更新

这是我最新的尝试是不工作:

let tableText = Table("t2") 
let id = Expression<Int64>("id") 
let someColumn = Expression<String>("someColumn") 

let tableFts = VirtualTable("fts_table") 
let columnDocId = Expression<Int64>("docId") 


let ftsQuery = tableFts 
    .select(columnDocId) 
    .filter(tableFts.match("something")) 
let tableQuery = tableText 
    .filter((try db.prepare(ftsQuery)) 
     .contains(id))      // <-- error 

for row in try db.prepare(tableQuery) { 
    print(row[someColumn]) 
} 

其中具有contains(id)行引发错误:

Cannot convert value of type 'Expression' to expected argument type '@noescape (Row) throws -> Bool'

+0

您是否有示例代码片段和失败?你想做什么不起作用? – stephencelis

+0

@stephencelis,我已添加更新。在这次最新的尝试中,我尝试将它分解为两个查询,因为我不知道有任何方法可以在单个查询中执行。 – Suragch

+0

我不相信你能够在FTS表的查询中使用表达式。如果您查看fts表的db模式,您会注意到type列是空的,而不是显示预期的类型(如常规表中所述)。不确定为什么sqlite会像这样工作,但我已经能够工作的唯一一件事是循环遍历返回的语句行。想知道你是否能够进一步提高这一点。 –

回答

1

我最终只是运行原始的SQL命令。这并不完全回答我在问题中提出的问题(因为它不使用纯SQLite.swift API),但对于那些只需要得到某些工作的人来说......可以工作。

这里是我从我的一些源代码中提取的一个修改后的示例。

static func findLinesContaining(_ searchTerms: String, forSearchScope scope: SearchScope) throws -> [TextLines] { 

    guard let db = SQLiteDataStore.sharedInstance.TextDB else { 
     throw DataAccessError.datastore_Connection_Error 
    } 

    // TODO: convert to SQLite.swift syntax rather than using a SQL string 
    var statement: Statement? = nil 
    switch scope { 
    case .wholeCollection: 
     statement = try db.run("SELECT bookId, chapterId, lineId, lineText" + 
      " FROM lines" + 
      " WHERE rowid IN (SELECT docid FROM fts_table" + 
      " WHERE fts_table MATCH ?);", searchTerms) 

    case .singleBook(let chosenBookId): 
     statement = try db.run("SELECT bookId, chapterId, lineId, lineText" + 
      " FROM lines" + 
      " WHERE rowid IN (SELECT docid FROM fts_table" + 
      " WHERE fts_table MATCH ?) AND bookId = ?;", [searchTerms, chosenBookId]) 
    } 


    var returnList: [TextLine] = [] 
    for row in statement! { 

     let line = TextLine() 
     if let bookId = row[0] as? Int64, 
      let chapterId = row[1] as? Int64, 
      let lineId = row[2] as? Int64, 
      let text = row[3] as? String { 

      line.bookId = Int(bookId) 
      line.chapterId = Int(chapterId) 
      line.lineId = Int(lineId) 
      line.lineText = text 
     } 

     returnList.append(line) 
    } 

    return returnList 
} 

上面的代码在重命名用于SO的变量和类之后未经测试。如果您发现错误,您有权限编辑代码。

+0

谢谢!我尝试了类似的东西,但没有使用参数占位符(?);我将继续前进。 +1的有用份额。 –