0

此功能向我显示“准备错误#0:没有这样的表:项目”的错误。有人可以帮我解决这个错误吗?

- (void)viewDidLoad
    {
    [super viewDidLoad];
    const char *dbpath = [databasePath UTF8String];
    sqlite3_stmt *statement;

    if (sqlite3_open(dbpath, &contactDB)== SQLITE_OK)
    {
        NSString *querySQL = [NSString stringWithFormat:@"Select name FROM items"];
        const char *query_stmt = [querySQL UTF8String];

        if (sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL) == SQLITE_OK)
        { NSLog(@"Data not fetched");
            if (sqlite3_step(statement) == SQLITE_ROW)
            {NSLog(@"Prepare-error #%i: %s", (sqlite3_prepare_v2(contactDB, [querySQL  UTF8String], -1, &statement, NULL) == SQLITE_OK), sqlite3_errmsg(contactDB));
                NSString *namefeild = [[NSString alloc]initWithUTF8String:(const char *)  sqlite3_column_text(statement, 0)];
                [list objectAtIndex:namefeild];
            }
            else{
                NSLog(@"Data not fetched");
            }
            sqlite3_finalize(statement);
        }else {NSLog(@"Prepare-error #%i: %s", (sqlite3_prepare_v2(contactDB, query_stmt,  -1, &statement, NULL) == SQLITE_OK), sqlite3_errmsg(contactDB));}
        sqlite3_close(contactDB);
    }

这两个函数是 n 个不同的视图控制器。

在视图 didload 中创建了数据库。

- (void)viewDidLoad
{
[super viewDidLoad];
NSString *docsDir;
NSArray *dirPath;
dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,  YES);
docsDir = [dirPath objectAtIndex:0];
databasePath = [[NSString alloc]initWithString:[docsDir  stringByAppendingPathComponent:@"contactDB"]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath] == NO) {
    const char *dbpath = [databasePath UTF8String];
    if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK) {
        char *errMsg;
        const char  *sql_stmt = "create table if not exists items(name varchar, price integer, description varchar)";
        if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
        {
            NSLog(@"Fail to create table");
        }
        sqlite3_close(contactDB);
    }else{
        NSLog(@"Failed to open database");
    }
}


}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

并在保存操作中将数据添加到数据库中。

- (IBAction)save:(id)sender {
sqlite3_stmt *statement;
const char *dbpath = [ databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK) {
    NSString *insertSQL = [NSString stringWithFormat:@"insert into items(name, price, description) values (\"%@\",\"%@\",\"%@\")", nametxt.text, pricetxt.text, description.text];
    const char *insert_stmt = [insertSQL UTF8String];
    sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
    if (sqlite3_step(statement) == SQLITE_DONE)
    {
        NSLog(@"contact added");
        nametxt.text= @"";
        pricetxt.text = @"";
        description.text = @"";
    }else{
        NSLog(@"Failed to add contact");
    }
    sqlite3_finalize(statement);
    sqlite3_close(contactDB);
 }
}
4

2 回答 2

1
- (void)viewDidLoad
 {
    [super viewDidLoad];
    const char *dbpath = [databasePath UTF8String];

    NSLog("%@", databasePath);

    ...
    ...
}

将数据库路径复制到剪贴板并将其粘贴到控制台中。

  1. cd "[数据库路径]"
  2. sqlite3 数据库文件名.db
  3. 。倾倒

在 .dump 命令之后,您是否看到表的创建语句?如果没有,那么您需要仔细检查您实际创建数据库的位置。如果您使用 .dump 命令的内容更新您的答案,这实际上会非常有帮助。

于 2013-10-16T15:28:06.540 回答
1

通常这意味着您打开的数据库中不存在该表。~/Library/Application Support/iPhone Simulator您应该在模拟器的 Documents 文件夹(我怀疑它不会在那里。

这个问题的一个常见原因是文件databasePath不存在(例如,您可能在捆绑包中有数据库副本,但没有 Documents 文件夹),在这种情况下,sqlite3_open将悄悄地在databasePath.

假设您不希望它在找不到它时创建一个空白数据库,您应该:

  • 从模拟器/设备中删除您的应用程序(以便删除任何空白数据库);

  • 检查您的原始打开例程并使用它NSFileManager来检查数据库是否存在(可能在继续之前将数据库从捆绑包复制到文档);

    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:databasePath]) {
        NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"itemsdb" ofType:@"sqlite"];
        [fileManager copyItemAtPath:bundlePath toPath:databasePath error:nil];
    }
    

    或者,如果数据库不存在,您的代码可能应该动态创建表,但想法是一样的。在打开文件之前检查文件是否存在。

  • 或许以后可以考虑使用sqlite3_open_v2withSQLITE_OPEN_READWRITE选项(而不是选项),它不会为SQLITE_OPEN_CREATE你创建数据库,如果找不到数据库会报错。


说了上面的话(当有人遇到像你这样的错误时,这是​​总法律顾问,你知道“应该”在那里的表不存在),在你处理错误的方式上,你的代码示例存在一些独特的问题报告:

  • 如果 step 成功,则报告错误。当然,您的意思是仅在步骤失败时才这样做。

  • 您由于步骤生成的错误说“准备错误”。当然这应该是“步骤错误”。

  • 您的错误记录正在调用再次失败的函数以获取返回码。您应该在第一次调用该函数时保存返回码,这样您就不必再次调用它以获得错误消息。(这很重要,因为有时函数返回的值会更改并重置您的错误消息。不要再次调用失败的函数!)保存原始返回代码也更有效。

因此:

if (sqlite3_open(dbpath, &contactDB)== SQLITE_OK)
{
    NSString *querySQL = [NSString stringWithFormat:@"Select name FROM items"];
    const char *query_stmt = [querySQL UTF8String];

    int rc;  // variable to hold the return code

    if ((rc = sqlite3_prepare_v2(contactDB, query_stmt, -1, &statement, NULL)) == SQLITE_OK)
    {
        if ((rc = sqlite3_step(statement)) == SQLITE_ROW)
        {
            NSString *namefeild = [[NSString alloc]initWithUTF8String:(const char *)  sqlite3_column_text(statement, 0)];
            [list objectAtIndex:namefeild];
        }
        else {
            if (rc == SQLITE_DONE)
                NSLog(@"step found no data");
            else
                NSLog(@"step-error #%i: %s", rc, sqlite3_errmsg(contactDB));
        }
        sqlite3_finalize(statement);
    } else {
        NSLog(@"Prepare-error #%i: %s", rc, sqlite3_errmsg(contactDB));
    }
    sqlite3_close(contactDB);
}
于 2013-10-16T12:44:00.317 回答