Passing an array to sqlite WHERE IN clause via FMDB?
Asked Answered
S

6

14

Is it possible to pass an array to a SELECT … WHERE … IN statement via FMDB? I tried to implode the array like this:

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

This only works if there is exactly 1 object in the array, which leads me to believe that FMDB adds quotes around the whole imploded string.

So I tried passing the array as is to FMDB's method:

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

Which doesn't work at all.

I didn't find anything about it in the README or the samples on FMDB's github page.

Thanks, Stefan

Shanty answered 5/12, 2011 at 10:8 Comment(0)
S
2

I created a simple FMDB extension to solve the problem:

FMDB+InOperator on GitHub

Shanty answered 6/10, 2015 at 20:1 Comment(0)
M
13

I was having the same issue, and I figured it out, at least for my own app. First, structure your query like so, matching the number of question marks as the amount of data in the array:

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

Then use the executeQuery:withArgumentsInArray call:

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

In my case, I had an array of NSString objects inside the NSArray named dataIDs. I tried all sorts of things to get this SQL query working, and finally with this combination of sql / function call, I was able to get proper results.

Mccullough answered 18/7, 2012 at 7:41 Comment(0)
S
10

Well I guess I have to use executeQueryWithFormat (which, according to FMDB documentation is not the recommended way). Anyway, here's my solution:

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];
Shanty answered 12/12, 2011 at 18:46 Comment(2)
But somehow this still doesn't work when the objects are NSStrings instead of NSNumbers. :-(Shanty
This won't work. SQL sanitization will see this a single variable.Nonresident
M
7

Adding onto Wayne Liu, if you know that the strings do not contain single or double quotes, you could simply do:

NSString * delimitedString = [strArray componentsJoinedByString:@"','"];
NSString * sql = [NSString stringWithFormat:@"SELECT * FROM tableName WHERE fieldName IN ('%@')", delimitedString];
Malvaceous answered 22/2, 2014 at 18:51 Comment(0)
C
5

If the keys are strings, I use the following code to generate the SQL command:

(assume strArray is an NSArray containing NSString elements)

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

Please note: if any elements in strArray could potentially contain the "double quote" symbols, you need to write extra codes (before these 2 lines) to escape them by writing 2 double quotes instead.

Catabolism answered 15/2, 2012 at 7:49 Comment(0)
S
2

I created a simple FMDB extension to solve the problem:

FMDB+InOperator on GitHub

Shanty answered 6/10, 2015 at 20:1 Comment(0)
J
0

Here's a Swift extension for FMDatabase that breaks array query parameters into multiple named parameters.

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

}

Example:

let sql = "SELECT * FROM things WHERE id IN :thing_ids"
let rs = db.executQuery(sql, params: ["thing_ids": [1, 2, 3]])
Jackquelin answered 9/6, 2015 at 16:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.