一對夫婦的想法:
這是最好的,如果列名沒有有他們的空間。如果您有空格,則需要將列名稱放在引號中,例如
Select * from TableName where entity1 = 'S' AND 'entity 2' = '100S'
最好通過確保列名中沒有空格來完全繞過此問題,例如, entity2
而不是entity 2
。
與其使用stringWithFormat
構建SQL,在SQL中使用?
佔位符並使用sqlite3_bind_text()
來設置值更安全。這樣,如果變量具有可能會混淆手動創建的SQL語句的任何字符(例如該字段具有單引號字符'
),則它會繞過該問題。所以,你可能有:
sqlite3 *database;
if (sqlite3_open([databasePath UTF8String], &database) != SQLITE_OK)
NSLog(@"%s open error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(database), sqlite3_errcode(database));
NSString *sql = @"Select * from TableName where entity1 = ? AND entity2 = ?";
NSString *entity1 = @"S";
NSString *entity2 = @"100S";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [sql UTF8String], -1, &statement, NULL) != SQLITE_OK)
NSLog(@"%s prepare SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(database), sqlite3_errcode(database));
if (sqlite3_bind_text(statement, 1, [entity1 UTF8String], -1, NULL) != SQLITE_OK)
NSLog(@"%s bind entity 1 error '%s'", __FUNCTION__, sqlite3_errmsg(database));
if (sqlite3_bind_text(statement, 2, [entity2 UTF8String], -1, NULL) != SQLITE_OK)
NSLog(@"%s bind entity 2 error '%s'", __FUNCTION__, sqlite3_errmsg(database));
int rc;
while ((rc = sqlite3_step(statement)) == SQLITE_ROW)
{
// do whatever you want with the results
const unsigned char *entity1 = sqlite3_column_text(statement, 0);
const unsigned char *entity2 = sqlite3_column_text(statement, 1);
const unsigned char *entity3 = sqlite3_column_text(statement, 2);
NSLog(@"%s %s %s", entity1, entity2, entity3);
}
if (rc != SQLITE_DONE)
NSLog(@"%s step SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(database), sqlite3_errcode(database));
sqlite3_finalize(statement);
sqlite3_close(database);
誠然,這使用的是sqlite_bind_text
多一點麻煩,但它更健壯。如果您不能完全確定您要查找的字段是否具有單引號字符,則使用此約定很重要。如果您正在根據用戶提供的某些搜索條件構建SQL(例如,找到「喬的酒吧和燒烤」,如果你不使用sqlite3_bind_text
或其他代碼圍繞這個問題,「喬的」撇號可能會導致你有點心痛。雖然這不是一個應用程序比網站的問題,但你根本不想讓你的應用程序易受SQL injection影響。
如果使用FMDB,一個美妙的小的Objective-C包裝SQLite的上述sqlite_bind_text
語法大大簡化:
FMDatabase *database = [FMDatabase databaseWithPath:databasePath];
NSAssert(database, @"unable to open database");
if (![database open])
NSLog(@"%@", [self.database lastErrorMessage]);
FMResultSet *rs = [database executeQuery:@"Select * from TableName where entity1 = ? AND entity2 = ?", @"S", @"100S"];
NSAssert(rs, [self.database lastErrorMessage]);
while ([rs next])
{
NSLog(@"%@ %@ %@", rs[0], rs[1], rs[2]);
}
[rs close];
[database close];
該享有的sqlite_bind_text
好處,而拖你通過sqlite
的雜草函數調用。
如果你想有,你可以使用的可變參數數目調用一個函數,你能做到這一點一堆不同的方式,動態建立你的SQL。我將在下面提供一個免責聲明的例子,我真的不喜歡手動構建SQL,因爲代碼最終會遇到可讀性問題。我寧願犧牲更簡潔的代碼,但我從你的問題推斷出你想知道如何動態構建你的SQL,所以我會提供一個示例,並提供上述警告。我也會說有很多方法可以解決這個問題,這只是一個例子。
無論如何,我們假設您想使用字典作爲哪些列具有哪些值的參數,您可以按如下方式調用它。如果你只有實體1,你會打電話,像這樣:
[self selectTableWithDictionary:@{@"entity1":@"S"}];
或者,如果你有兩個實體1和實體2,你會叫它像這樣:
[self selectTableWithDictionary:@{@"entity1":@"S", @"entity2":@"100S"}];
的方法以然後解析該字典,手動構建SQL,然後綁定各個列可能類似於:
- (void)selectWithDictionary:(NSDictionary *)dictionary
{
NSArray *fieldNames = [dictionary allKeys];
NSArray *values = [dictionary allValues];
// build the sql
NSMutableString *sql = [NSMutableString stringWithString:@"Select * from TableName"];
if ([fieldNames count]){
[sql appendString:@" where "];
[sql appendString:[fieldNames componentsJoinedByString:@" = ? AND "]];
[sql appendString:@" = ?"];
}
sqlite3_stmt *statement;
// prepare the sql
if (sqlite3_prepare_v2(database, [sql UTF8String], -1, &statement, NULL) != SQLITE_OK)
NSLog(@"%s prepare SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(database), sqlite3_errcode(database));
// bind the values
for (NSInteger i = 0; i < [fieldNames count]; i++)
if (sqlite3_bind_text(statement, i+1, [values[i] UTF8String], -1, NULL) != SQLITE_OK)
NSLog(@"%s bind column # %d error '%s'", __FUNCTION__, i+1, sqlite3_errmsg(database));
int rc;
// iterate through the results
while ((rc = sqlite3_step(statement)) == SQLITE_ROW)
{
const unsigned char *entity1 = sqlite3_column_text(statement, 0);
const unsigned char *entity2 = sqlite3_column_text(statement, 1);
const unsigned char *entity3 = sqlite3_column_text(statement, 2);
NSLog(@"%s %s %s", entity1, entity2, entity3);
}
if (rc != SQLITE_DONE)
NSLog(@"%s step SQL error '%s' (%1d)", __FUNCTION__, sqlite3_errmsg(database), sqlite3_errcode(database));
sqlite3_finalize(statement);
}
的FMDB實現可能看起來像:
- (void)selectTableWithDictionary:(NSDictionary *)dictionary
{
NSArray *fieldNames = [dictionary allKeys];
NSArray *values = [dictionary allValues];
// build the sql
NSMutableString *sql = [NSMutableString stringWithString:@"Select * from TableName"];
if ([fieldNames count]){
[sql appendString:@" where "];
[sql appendString:[fieldNames componentsJoinedByString:@" = ? AND "]];
[sql appendString:@" = ?"];
}
// execute the sql
FMResultSet *rs = [self.database executeQuery:sql
withArgumentsInArray:values];
NSAssert(rs, [self.database lastErrorMessage]);
// iterate through the results
while ([rs next])
{
NSLog(@"%@ %@ %@", rs[0], rs[1], rs[2]);
}
[rs close];
}
什麼是實體1,2和3的含義? –
當我選擇表中的值並執行動態查詢時,我必須追加字符串。你記得概率嗎? – Roma
你可以給我你的郵件ID – Roma