0

この関数は、「Prepare-error #0: no such table: items」というエラーを表示しています。このエラーを解決するのを手伝ってください。

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

これらの 2 つの関数は、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

通常、これは、開いたデータベースにテーブルが存在しないことを意味します。シミュレーターの Documents フォルダー ( ~/Library/Application Support/iPhone Simulator) にデータベースがあり、選択した MacOS SQLite ツールでデータベースを開き、テーブルがそこにあるかどうかを自分で確認してください。そこにはないと思います。

この問題の一般的な原因は、 にファイルが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_v2) を使用することを検討してください。SQLITE_OPEN_READWRITESQLITE_OPEN_CREATE


上記(これは、誰かがあなたのようなエラーに遭遇したときの一般的な助言であり、そこに「あるはず」であることがわかっているテーブルはありません)、エラーを処理する方法にはコードサンプルに固有の問題があります報告:

  • ステップが成功すると、エラーが報告されます。確かに、ステップが失敗した場合にのみそれを行うつもりでした。

  • ステップの結果として生成されるエラーには、「準備エラー」と表示されます。きっとそれは「ステップエラー」のはずです。

  • エラーのログは、リターン コードを取得するために再度失敗した関数を呼び出しています。関数を最初に呼び出したときのリターン コードを保存しておくと、エラー メッセージのために関数を再度呼び出す必要がなくなります。(関数によって返される値が変更され、エラー メッセージがリセットされる場合があるため、これは重要です。失敗した関数を再度呼び出さないでください!) また、元の戻りコードを保存する方が効率的です。

したがって:

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 に答える