2017-05-03 14 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 - '? 'プレースホルダではなく、値自体を補間するのは悪いですが、IMHOは手動で引用符を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) –

関連する問題