在 iOS 应用程序中没有从 sqlite3 获取行

发布于 2024-10-24 01:39:59 字数 1797 浏览 2 评论 0原文

以下代码不返回任何行,但是当我在终端中的 sqlite3 中运行查询时,我得到了我期望的结果。所以我想这里有一些微不足道的错误:

- (void)initializeDatabaseWithFilter:(NSString *)filter
{
    NSMutableArray *fristArray = [[NSMutableArray alloc] init];
    self.frister = fristArray;
    [fristArray release];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"Frister.sqlite"];
    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK){
        // Get primary key for all entries with filter
        const char *sql = "SELECT fristKey FROM frister WHERE ? = 1";
        sqlite3_stmt *statement;
        if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) {
            NSAssert1(0,@"Error: Failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
        }
        sqlite3_bind_text(statement, 1, [filter UTF8String], -1, SQLITE_TRANSIENT);
        NSLog(@"%@",filter); // lets me see if the filter column name is passed to the method.
        int i = 0; // this is to see if I get some rows in return
        while (sqlite3_step(statement) == SQLITE_ROW) {
            i++;
            int primaryKey = sqlite3_column_int(statement,0);
            Frist *td = [[Frist alloc] inithWithOwnerID:primaryKey database:database];

            [frister addObject:td];
            [td release];
        }
        NSLog(@"%d",i); // If I get some results, I should get a number here...
        sqlite3_finalize(statement);
    } else {
        sqlite3_close(database);
        NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
    }
}

我真的很想在这里得到一些帮助:)

The following code returns no rows, but when I run the query in sqlite3 in Terminal, I get the result I expect. So I guess there is some trivial mistake here:

- (void)initializeDatabaseWithFilter:(NSString *)filter
{
    NSMutableArray *fristArray = [[NSMutableArray alloc] init];
    self.frister = fristArray;
    [fristArray release];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"Frister.sqlite"];
    if (sqlite3_open([path UTF8String], &database) == SQLITE_OK){
        // Get primary key for all entries with filter
        const char *sql = "SELECT fristKey FROM frister WHERE ? = 1";
        sqlite3_stmt *statement;
        if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) != SQLITE_OK) {
            NSAssert1(0,@"Error: Failed to prepare statement with message '%s'.", sqlite3_errmsg(database));
        }
        sqlite3_bind_text(statement, 1, [filter UTF8String], -1, SQLITE_TRANSIENT);
        NSLog(@"%@",filter); // lets me see if the filter column name is passed to the method.
        int i = 0; // this is to see if I get some rows in return
        while (sqlite3_step(statement) == SQLITE_ROW) {
            i++;
            int primaryKey = sqlite3_column_int(statement,0);
            Frist *td = [[Frist alloc] inithWithOwnerID:primaryKey database:database];

            [frister addObject:td];
            [td release];
        }
        NSLog(@"%d",i); // If I get some results, I should get a number here...
        sqlite3_finalize(statement);
    } else {
        sqlite3_close(database);
        NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
    }
}

I would really like some help here :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

公布 2024-10-31 01:39:59

我看到您已经接受了答案,但我想我在您的 sqlite 调用中看到了问题。

在终端中,我猜您正在执行类似这样的查询:

SELECT fristKey FROM frister WHERE column = 1

但是您的代码没有执行等效的查询。相反,它执行如下查询:

SELECT fristKey FROM frister WHERE 'column' = 1

由于字符串“column”永远不会等于 1,因此您的查询不会给出任何结果。您不能将列名绑定到参数化查询中,只能将文字值绑定到参数化查询中。

I see you've already accepted an answer, but I think I see the problem in your sqlite call.

In the terminal, I guess you're doing a query something like this:

SELECT fristKey FROM frister WHERE column = 1

But your code is not doing an equivalent query. It is instead doing a query like this:

SELECT fristKey FROM frister WHERE 'column' = 1

Since the string "column" is never going to be equal to 1, your query is not going to give any results. You cannot bind a column name into a parameterized query, only a literal value.

兔姬 2024-10-31 01:39:59

(添加此作为答案,因为将其作为评论会非常麻烦)

我强烈建议使用 FMDB 与数据库交互。它是 SQLite C API 的包装器,使与数据库的交互变得非常容易。您的代码可以更改为以极少的干预来使用它。它看起来是这样的:

- (void)initializeDatabaseWithFilter:(NSString *)filter
{
    self.frister = [NSMutableArray array];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"Frister.sqlite"];

    FMDatabase *db = [FMDatabase databaseWithPath:path];
    if ([db open]) {
        NSString *sql = [NSString stringWithFormat:@"SELECT fristKey FROM frister WHERE %@ = 1", filter];
        FMResultSet *results = [db executeQuery:sql];
        while([results next]) {
            int primaryKey = [results intForColumn:@"fristKey"];
            Frist *td = [[Frist alloc] initWithOwnerID:primaryKey database:db];
            [[self frister] addObject:td];
            [td release];
        }
        [db close];
    }
}

这不是看起来更具可读性吗?很容易看出您正在执行查询,迭代结果,并拉出“fristKey”以创建“Frist”对象。您不必担心 sqlite3_open、准备语句、绑定参数或完成语句。

您必须更改的另一件事是 Frist 对象:它需要接受 FMDatabase* 因为它是“数据库”而不是 sqlite3*.您也可以考虑只打开数据库一次,然后将其保持打开状态,直到您不再需要它为止(否则每次您想要执行某些操作时都必须 -open 它;这完全是由你决定)。

要将 FMDB 包含在您的应用中,请从 Github 下载代码,然后将 FMDatabase、FMDatabaseAdditions 和 FMResultSet 文件(全部 6 个)复制到您的应用中,并在需要交互的位置#import 它们与数据库。您仍然需要链接 sqlite3.dylib。

请确保您遵守(非常宽松的)许可证

(Adding this as an answer since it would be pretty cumbersome to put it as a comment)

I strongly suggest using FMDB to interact with the database instead. It's a wrapper around the SQLite C API that makes it very easy to interact with a database. Your code could be changed to use it with pretty minimal intervention. Here's what it would look like:

- (void)initializeDatabaseWithFilter:(NSString *)filter
{
    self.frister = [NSMutableArray array];

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *path = [documentsDirectory stringByAppendingPathComponent:@"Frister.sqlite"];

    FMDatabase *db = [FMDatabase databaseWithPath:path];
    if ([db open]) {
        NSString *sql = [NSString stringWithFormat:@"SELECT fristKey FROM frister WHERE %@ = 1", filter];
        FMResultSet *results = [db executeQuery:sql];
        while([results next]) {
            int primaryKey = [results intForColumn:@"fristKey"];
            Frist *td = [[Frist alloc] initWithOwnerID:primaryKey database:db];
            [[self frister] addObject:td];
            [td release];
        }
        [db close];
    }
}

Doesn't that look a TON more readable? It's pretty easy to see that you're executing a query, iterating through the results, and pulling the "fristKey" out in order to make a "Frist" object. You don't have to worry about sqlite3_open, preparing statements, binding parameters, or finalizing statements.

The other thing you'd have to change is the Frist object: it needs to accept a FMDatabase* as it's "database" instead of a sqlite3*. You may also consider just opening the database once and then leaving it open until you don't need it anymore (otherwise you'll have to -open it every time you want to execute something; this is entirely up to you).

To include FMDB in your app, download the code from Github, and then copy the FMDatabase, FMDatabaseAdditions, and FMResultSet files (all 6) into your app, and #import them where you'll need to interact with the database. You'll still need to link against sqlite3.dylib.

Just be sure you honor the (very permissive) license.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文