-2

我想实现一个查询和一个动态查询。有 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'
4

3 回答 3

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有点麻烦,但更健壮。如果您不能完全确定要查找的字段是否包含单引号字符,则使用此约定很重要。如果您基于用户提供的某些搜索条件(例如查找“Joe's Bar and Grill”)构建 SQL,这一点至关重要,如果您不使用sqlite3_bind_text或不使用其他代码,“Joe's”中的撇号可能会让您有点心痛围绕这个问题)。虽然这对于应用程序来说比网站问题更小,但您根本不希望您的应用程序容易受到SQL 注入的影响。

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

    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];
}
于 2013-01-02T06:50:01.697 回答
0

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

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

希望对您有所帮助。

干杯!

于 2013-01-02T05:53:06.853 回答
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];
于 2013-01-02T06:32:16.987 回答