如何使用SQlite和iOS通过不同的用户ID获取最后一条消息?

时间:2014-04-28 13:32:44

标签: ios sql sqlite xcode5

我有一个"消息表" ,我只希望用他的上一条消息检索"用户ID"

我试图添加" 2 sql语句"在彼此内部,但它不停地循环,

   sqlite3_stmt *statement;
NSMutableArray * messages = [[NSMutableArray alloc]init];

const char *dbpath = [_databasePath UTF8String];
if (sqlite3_open(dbpath, &_chatDB) == SQLITE_OK)
{
    NSString *querySQL = [NSString stringWithFormat:
                          @"SELECT DISTINCT FROMID , USERNAME from CHATCOMPLETE"];
    const char *query_stmt = [querySQL UTF8String];
    if (sqlite3_prepare_v2(_chatDB,
                           query_stmt, -1, &statement, NULL) == SQLITE_OK)
    {
        while (sqlite3_step(statement) == SQLITE_ROW)
        {
            int userID = [[[NSString alloc] initWithUTF8String:
                          (const char *) sqlite3_column_text(statement, 0)] integerValue];

            NSString *querySQL2 = [NSString stringWithFormat:
                                  @"SELECT MESSAGE , USERNAME from CHATCOMPLETE where FROMID=\"%d\"",userID];
            const char *query_stmt2 = [querySQL2 UTF8String];
            if (sqlite3_prepare_v2(_chatDB,
                                   query_stmt2, -1, &statement, NULL) == SQLITE_OK)
            {
                while (sqlite3_step(statement) == SQLITE_ROW)
                {

                    NSLog(@"LAST MESSAGE %@",[[NSString alloc] initWithUTF8String:
                                               (const char *) sqlite3_column_text(statement, 0)]);

                    sqlite3_reset(statement);

                }
            }
        }
                    sqlite3_reset(statement);
    }
}
return messages;

更新 这是插入消息

    -(void)saveData:(NSString *)message toID:(int)toID fromID:(int)fromID isRead:(BOOL)read date:(NSDate *)date messageID:(int)messageID userName:(NSString*)userName
{
    sqlite3_stmt    *statement;

    const char *dbpath = [_databasePath UTF8String];

    if (sqlite3_open(dbpath, &_chatDB) == SQLITE_OK)
    {
        NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO CHATCOMPLETE (MESSAGE, TOID, FROMID, READ, date, MESSAGEID, USERNAME) VALUES (\"%@\", \"%d\", \"%d\", \"%c\", \"%@\", \"%d\", \"%@\")", message, toID, fromID, read, date,messageID,userName];

        const char *insert_stmt = [insertSQL UTF8String];

        sqlite3_prepare_v2(_chatDB, insert_stmt, -1, &statement, NULL);
        if (sqlite3_step(statement) == SQLITE_DONE)
        {
            NSLog(@"DONE");
          /*  status.text = @"Contact added";
            name.text = @"";
            address.text = @"";
            phone.text = @"";*/
        } else {
         //   status.text = @"Failed to add contact";
        }
        sqlite3_finalize(statement);
        sqlite3_close(_chatDB);
    }

}

3 个答案:

答案 0 :(得分:1)

这是获取给定fromID的最后一条消息的查询:

SELECT * FROM chatting WHERE fromID=9999 ORDER BY id DESC LIMIT 1

答案 1 :(得分:1)

在SQLite 3.7.11或更高版本中,以下查询将返回每个发件人的日期最长的邮件:

SELECT *, MAX(date)
FROM ChatComplete
GROUP BY FromID

答案 2 :(得分:0)

有一些问题:

  1. 您的两个嵌套查询只有一个sqlite3_stmt变量。您需要为每个单独的sqlite3_stmt

  2. 您正在呼叫sqlite3_reset。仅在将新值绑定到预准备语句中的?占位符时使用,这在此处不适用。更糟糕的是,你在循环中调用它。

  3. 与手头的问题无关,但是对于每个准备好的语句,在完成循环结果时不要忘记调用sqlite3_finalize,以释放准备语句时使用的内存。


  4. 因此,您可能需要以下内容:

    sqlite3_stmt *userStatement;
    sqlite3_stmt *messageStatement;
    int rc;                           // the return code
    NSMutableArray * messages = [[NSMutableArray alloc]init];
    
    const char *dbpath = [_databasePath UTF8String];
    if (sqlite3_open(dbpath, &_chatDB) == SQLITE_OK)
    {
        const char *query_stmt = "SELECT DISTINCT FROMID , USERNAME from CHATCOMPLETE";
        if (sqlite3_prepare_v2(_chatDB, query_stmt, -1, &userStatement, NULL) != SQLITE_OK)
        {
            NSLog(@"%s: prepare userStatement failed: %s", __PRETTY_FUNCTION__, sqlite3_errmsg(_chatDB));
        }
        else 
        {
            while ((rc = sqlite3_step(userStatement)) == SQLITE_ROW)
            {
                int userID = [[[NSString alloc] initWithUTF8String:
                              (const char *) sqlite3_column_text(statement, 0)] integerValue];
    
                const char *query_stmt2 = "SELECT MESSAGE , USERNAME from CHATCOMPLETE where FROMID=? ORDER BY timestamp DESC LIMIT 1"; // change the `ORDER BY` to use whatever field you want to sort by
    
                if (sqlite3_prepare_v2(_chatDB, query_stmt2, -1, &messageStatement, NULL) != SQLITE_OK)
                {
                    NSLog(@"%s: prepare messageStatement failed: %s", __PRETTY_FUNCTION__, sqlite3_errmsg(_chatDB));
                }
                else 
                {
                    if (sqlite3_bind_int(messageStatement, 1, userID) != SQLITE_OK) 
                    {
                        NSLog(@"%s: bind userID %d failed: %s", __PRETTY_FUNCTION__, userID, sqlite3_errmsg(_chatDB));
                    }
    
                    while ((rc = sqlite3_step(messageStatement)) == SQLITE_ROW)
                    {
                        NSLog(@"LAST MESSAGE %@",[[NSString alloc] initWithUTF8String:
                                                   (const char *) sqlite3_column_text(statement, 0)]);
                    }
                    if (rc != SQLITE_DONE)
                    {
                        NSLog(@"%s: step messageStatement failed: %s", __PRETTY_FUNCTION__, sqlite3_errmsg(_chatDB));
                    }
    
                    sqlite3_finalize(messageStatement);
                }
            }
            if (rc != SQLITE_DONE) 
            {
                NSLog(@"%s: step userStatement failed: %s", __PRETTY_FUNCTION__, sqlite3_errmsg(_chatDB));
            }
    
            sqlite3_finalize(userStatement);
        }
    }
    else
    {
        NSLog(@"%s: open %@ failed", __PRETTY_FUNCTION__, _databasePath);
    }
    return messages;
    

    请注意,除了上述三点之外,此代码示例还包括:

    1. 如果sqlite3_errmsg失败,请使用sqlite3_prepare_v2记录错误。

    2. 添加了对sqlite3_step返回代码的检查,如果失败则再次记录sqlite3_errmsg

    3. 如果sqlite3_open失败,则添加日志。

    4. 使用sqlite3_bind_int()而不是使用stringWithFormat构建SQL。在这种情况下,因为userID是数字,这不是关键,但如果在WHERE子句中使用字符串值,使用sqlite3_bind_text()函数变得至关重要,所以我只是想表现出这种模式。

      例如,查看保存例程并尝试保存恰好带有双引号的消息(例如I spoke with Bob and he says "hello" to you.)。您的stringWithFormat构造将失败。如果您使用sqlite3_bind_text,它将解决该问题。

    5. BTW,正如您所看到的,当您添加所有正确的结果验证,绑定值等时,代码变得有点笨拙。您可以考虑使用FMDB,这极大地简化了您的SQLite Objective-C代码。