0

次の SQL ステートメントがあります。

const char* sqlStatement = "SELECT ((? - deal.latitude) * (? - deal.latitude) + (? - deal.longitude) * (? - deal.longitude)) AS distance, id, title, shop, latitude, longitude FROM deal WHERE (type = ?) AND category IN (?) AND tribe IN (?) ORDER BY distance LIMIT 20;";

// ...

sqlite3_bind_double(preparedStatement, 1, location.latitude);
sqlite3_bind_double(preparedStatement, 2, location.latitude);
sqlite3_bind_double(preparedStatement, 3, location.longitude);
sqlite3_bind_double(preparedStatement, 4, location.longitude);
sqlite3_bind_int(preparedStatement, 5, type);
sqlite3_bind_text(preparedStatement, 6, [categories UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(preparedStatement, 7, [tribes UTF8String], -1, SQLITE_TRANSIENT);

ここで、6 番目と 7 番目の引数はクエリが失敗する原因になります。

while (sqlite3_step(preparedStatement) == SQLITE_ROW) {

実行されません。カテゴリと部族は次のように構築されます。

NSArray* userCategories = [CategoryDataController getUserCategories];
NSMutableString* categories = [[NSMutableString alloc] init];

for (NSNumber *category in userCategories) {
    [categories appendString:[[NSString alloc] initWithFormat:@"%@, ", category]];
}
if ([categories length] > 0) {
    categories = (NSMutableString *)[categories substringToIndex:[categories length] - 2];
}

NSArray* userTribes = [TribeDataController getUserTribes];
NSMutableString* tribes = [[NSMutableString alloc] init];

for (NSNumber* tribe in userTribes) {
    [tribes appendString:[[NSString alloc] initWithFormat:@"%@, ", tribe]];
}
if ([tribes length] > 0)
    tribes = (NSMutableString *)[tribes substringToIndex:[tribes length] - 2];

userCategories と userTribes は NSNumber の配列です。部族とカテゴリをログに記録すると、次のような適切な形式の文字列が得られます。

1, 2, 3, 4, 5

奇妙なことに、代わりに sqlite3_bind_ 関数を使用して、次のようにクエリを作成します。

NSString *sqlStatementNSString = [[NSString alloc] initWithFormat:@"SELECT ((%f - deal.latitude) * (%f - deal.latitude) + (%f - deal.longitude) * (%f - deal.longitude)) AS distance, id, title, shop, latitude, longitude FROM deal WHERE type = %d AND category IN (%@) AND tribe IN (%@) ORDER BY distance LIMIT 20;", location.latitude, location.latitude, location.longitude, location.longitude, type, categories, tribes];
const char *sqlStatement = [sqlStatementNSString UTF8String];

できます!私が間違っていることは何ですか?事前に感謝します(そして、私の英語で申し訳ありません)。

4

1 に答える 1

0

私もこれに対する答えを探しましたが、一般に、準備されたステートメントは IN 演算子をサポートしていないようです。このサイトで見つけることができるあらゆる種類のソリューションがあります。私の好ましい解決策(回答の1つから得られたもの)は、IN演算子リストに固定数のスロットを持つステートメントを準備することです:

SELECT * FROM db WHERE id IN (?, ?, ?, ?, ?, ?)

次に、((n + 5) / 6) 回 (この例では) クエリを実行し、すべての回答をマージします。スロットの数が少ない場合は、残りを NULL で埋めるか、最後のエントリを複製します。オプティマイザーは、うまくいけば、重複した比較を避けるべきです。

準備されたステートメントを再利用することは、おそらくカスタム クエリ文字列を作成して実行するよりも高速です (ただし、プロファイルを確認してください!)

于 2012-05-15T18:40:47.263 に答える