如何在iphone sdk中实现动态查询

时间:2013-01-02 05:43:45

标签: iphone objective-c ios

我想实现单个查询和动态查询。 我有4个表,我可以使用group by子句过滤表。 但现在我想结合这四个表并进行动态查询。 选择值t将如下所示 例如:

NSString *strQuery = @"Select * from TableName where "

步骤:1:

entity1查询将是:

Select * from TableName where entity1 = 'S'

步骤:2

实体2查询将是:

Select * from TableName where entity1 = 'S' AND entity 2 = '100S' 

步骤:3

实体3查询将是:

Select * from TableName where entity1 = 'S' AND entity 2 = '100S' AND entity3 = 'Fly'

3 个答案:

答案 0 :(得分:1)

有几点想法:

  1. 最好是列名称中没有空格。如果您有空格,则需要将列名称放在引号中,例如

    Select * from TableName where entity1 = 'S' AND 'entity 2' = '100S'
    

    最好通过确保列名称中没有空格来完全绕过此问题,例如: entity2而不是entity 2

  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,这一点至关重要(例如,查找“Joe's Bar and Grill”,如果您不使用{{1,那么“Joe's”中的撇号可能会让您有点心痛或者围绕这个问题编写代码)。虽然这不是一个应用程序的问题,而是一个网站,你只是不希望你的应用程序易受SQL injection

  3. 如果使用FMDB,这是SQLite的一个很棒的Objective-C包装器,上面的sqlite3_bind_text语法会大大简化:

    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函数调用的杂草。


  4. 如果你想拥有一个可以使用可变数量的参数调用的函数,你可以通过一系列不同的方式来实现,动态构建SQL。我将在下面提供一个免责声明示例,我真的不喜欢手动构建SQL,因为代码最终会遇到可读性问题。我宁愿用简洁易懂的东西来牺牲简约代码,但我从你的问题中推断出你想知道如何动态地构建你的SQL,所以我将提供一个样本,但有上述警告。我还会说有很多方法可以解决这个问题,而这只是一个这样的例子。

    无论如何,我们假设您要使用字典作为哪些列具有哪些值的参数,您可以按如下方式调用它。如果您只有实体1,那么您可以这样称呼:

    sqlite

    或者,如果您同时拥有实体1和实体2,则可以这样称呼它:

    [self selectTableWithDictionary:@{@"entity1":@"S"}];
    

    然后解析此字典,手动构建SQL,然后绑定各列的方法可能如下所示:

    [self selectTableWithDictionary:@{@"entity1":@"S", @"entity2":@"100S"}];
    

    FMDB实现可能如下所示:

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

答案 1 :(得分:0)

您可以尝试使用NSString的“stringWithFormat”方法,

NSString *strQuery = [NSString stringWithFormat:@"Select * from TableName where entity1 = '%@' AND entity 2 = '%@'",@"S",@"100S"];

希望它对你有所帮助。

干杯!

答案 2 :(得分:0)

对于静态值您可以尝试

NSString *strQuery =@"Select * from TableName where entity1 = 'S' AND entity 2 = '100S'";

对于动态值,您可以尝试

NSString *strQuery = [NSString stringWithFormat:@"Select * from TableName where entity1 = '%@' AND entity 2 = '%@'",entity1_obj,entity2_obj];