2017-05-03 36 views
0

我需要在编译时使用长度未知的参数数组运行SQLite查询(如果需要,我可以使用FMDB,但可以使用本地SQLite)。到目前为止,我已经根据数组长度手动将正确数量的绑定插入到字符串中:将任意长度的数组绑定到SQLite查询

func getBindString (_ arrayCount: Int) -> String { 
    return [String](repeating: "?", count: arrayCount).joined(separator: ",") 
} 

let someArray = ["foo","bar"] 
let sqlString = "delete from someTable where someColumn in (\(getBindString(someArray.count)))" 
db.executeUpdate(sqlString, withArgumentsIn: someArray) 
/* delete from someTable where someColumn in ('foo','bar') */ 

这只是感觉真的很不雅观。有没有处理这个问题的“适当”方法?我在网上找到的所有东西都过时了几年,所有推荐的内容直接插值,这更糟糕。

+1

@matt - 插值的自己,而不是'?'占位符,更糟糕,恕我直言,因为你然后手动插入引号到SQL中,可以有问题的价值观,他们本身有任何引号或任何受SQL字符串转义的东西。通过使用适当数量的'?'占位符构建SQL,可以避免一系列可能的问题。 – Rob

+0

@Rob不错的一点,谢谢。 – matt

回答

1

我不明白这是什么“不雅”。您正在使用基于字符串的语言(SQL),并且您非常整齐地形成字符串实时。

你的代码与我亲自写的不完全相同;我不喜欢在不需要它的字符串插值,并且在这里不需要,所以我建议更多的东西像这样(我也觉得这是很好的使用map而非Array(repeating:)):

let someArray = ["foo","bar"] 
let bindString = someArray.map{_ in "?"}.joined(separator: ",") 
let sqlString = "delete from someTable where someColumn in (" + bindString + ")" 

如果你必须多次形成像bindString这样的字符串,那么通过一切手段将它变成一个效用函数。但后来我会写作为阵列的扩展:

extension Array { 
    var bindString : String { 
     return "(" + self.map{_ in "?"}.joined(separator: ",") + ")" 
    } 
} 

这样一来,你的字符串结构是这样的:

let someArray = ["foo","bar"] 
let sqlString = "delete from someTable where someColumn in " + someArray.bindString 

但所有这一切纯粹是文体的调整;有没有与你在做什么不对。

+0

这个扩展没有太多的自然收集:为了提供'值IN(?,...)',一个Set和一个数组一样。 GRDB定义了一个全局函数:['databaseQuestionMarks(count:)'](https://github.com/groue/GRDB.swift/blob/v0.106.1/GRDB/Core/Utils.swift#L23-L25) –