通过 FMDB 将数组传递给 sqlite WHERE IN 子句?

Posted

技术标签:

【中文标题】通过 FMDB 将数组传递给 sqlite WHERE IN 子句?【英文标题】:Passing an array to sqlite WHERE IN clause via FMDB? 【发布时间】:2012-01-13 02:19:56 【问题描述】:

是否可以通过 FMDB 将数组传递给 SELECT ... WHERE ... IN 语句? 我试图像这样内爆数组:

NSArray *mergeIds; // An array with NSNumber Objects
NSString *mergeIdString = [mergeIds componentsJoinedByString:@","];

NSString *query = @"SELECT * FROM items WHERE last_merge_id IN (?)";
FMResultSet *result = [database executeQuery:query, mergeIdString];

这仅在数组中只有 1 个对象时才有效,这让我相信 FMDB 在整个内爆字符串周围添加引号。

所以我尝试将数组按原样传递给 FMDB 的方法:

NSArray *mergeIds; // An array with NSNumber Objects
NSString *query = @"SELECT * FROM items WHERE last_merge_id IN (?)";
FMResultSet *result = [database executeQuery:query, mergeIds];

这根本不起作用。

我在 README 或 FMDB 的 github 页面上的示例中没有找到任何相关内容。

谢谢,斯特凡

【问题讨论】:

【参考方案1】:

我创建了一个简单的 FMDB 扩展来解决这个问题:

FMDB+InOperator on GitHub

【讨论】:

【参考方案2】:

这是 FMDatabase 的 Swift 扩展,它将数组查询参数分解为多个命名参数。

extension FMDatabase 

    func executeQuery(query: String, params:[String: AnyObject]) -> FMResultSet? 

        var q = query
        var d = [String: AnyObject]()
        for (key, val) in params 
            if let arr = val as? [AnyObject] 
                var r = [String]()
                for var i = 0; i < arr.count; i++ 
                    let keyWithIndex = "\(key)_\(i)"
                    r.append(":\(keyWithIndex)")
                    d[keyWithIndex] = arr[i]
                
                let replacement = ",".join(r)
                q = q.stringByReplacingOccurrencesOfString(":\(key)", withString: "(\(replacement))", options: NSStringCompareOptions.LiteralSearch, range: nil)
            
            else 
                d[key] = val
            
        

        return executeQuery(q, withParameterDictionary: d)
    


例子:

let sql = "SELECT * FROM things WHERE id IN :thing_ids"
let rs = db.executQuery(sql, params: ["thing_ids": [1, 2, 3]])

【讨论】:

【参考方案3】:

添加到 Wayne Liu,如果您知道字符串不包含单引号或双引号,您可以这样做:

NSString * delimitedString = [strArray componentsJoinedByString:@"','"];
NSString * sql = [NSString stringWithFormat:@"SELECT * FROM tableName WHERE fieldName IN ('%@')", delimitedString];

【讨论】:

【参考方案4】:

我遇到了同样的问题,并且我想通了,至少在我自己的应用程序中是这样。首先,像这样构造您的查询,将问号的数量与数组中的数据量相匹配:

NSString *getDataSql = @"SELECT * FROM data WHERE dataID IN (?, ?, ?)";

然后使用executeQuery:withArgumentsInArray 调用:

FMResultSet *results = [database executeQuery:getDataSql withArgumentsInArray:dataIDs];

在我的例子中,我在名为 dataIDs 的 NSArray 中有一个 NSString 对象数组。我尝试了各种方法来让这个 SQL 查询正常工作,最后通过这种 sql / 函数调用的组合,我能够得到正确的结果。

【讨论】:

【参考方案5】:

如果键是字符串,我使用以下代码生成 SQL 命令:

(假设 strArray 是一个包含 NSString 元素的 NSArray)

NSString * strComma = [strArray componentsJoinedByString:@"\", \""];
NSString * sql = [NSString stringWithFormat:@"SELECT * FROM tableName WHERE fieldName IN (\"%@\")", strComma];

请注意:如果 strArray 中的任何元素可能包含“双引号”符号,则需要编写额外的代码(在这两行之前)通过编写 2 个双引号来转义它们。

【讨论】:

【参考方案6】:

好吧,我想我必须使用executeQueryWithFormat(根据 FMDB 文档,这不是推荐的方式)。无论如何,这是我的解决方案:

NSArray *mergeIds; // An array of NSNumber Objects
NSString *mergeIdString = [mergeIds componentsJoinedByString:@","];

NSString *query = @"SELECT * FROM items WHERE last_merge_id IN (?)";
FMResultSet *res = [self.database executeQueryWithFormat:query, mergeIdString];

【讨论】:

但不知何故,当对象是 NSStrings 而不是 NSNumbers 时,这仍然不起作用。 :-( 这行不通。 SQL 清理将看到这是一个单一的变量。

以上是关于通过 FMDB 将数组传递给 sqlite WHERE IN 子句?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 FMDB 将数据保存和检索到 sqlite

将多个 SQLite 数据库与 FMDB 进行比较

iOS SQLite FMDB 事务.. 正确用法?

FMDB之数组字典的存储

FMDB,sqlite json-string 成字典?

带有 FMDB 的 iOS SQLite 在仅通过 TestFlight 分发临时构建时不断报告“内存不足”错误