6

我试图在运行时通过 Objective-C 创建一个 SQLite3 数据库文件。我正在尝试创建一个名为“tblStore”的表。我希望将字段名称称为“strStoreNumber”和“strStoreReg”。我是 iOS 和 SQLite 的新手,所以我很难找到执行此操作的语法。除了创建表之外,我希望创建的表不驻留在应用程序包中,而是驻留在/存储在手机上的某个位置。该表需要是可读/可写的。我已经阅读了“用户沙箱”和“文档目录”。我不确定我是否理解两者之间的区别。理想情况下,我的应用程序将使用一个按钮从文本字段中获取输入。将文本字段的输入放入字符串后,

回顾一下: 1. Obj-C/SQLite 创建一个名为“tblStore”的表,其中包含“strStoreNumber”和“strStoreReg”字段的语法是什么?2.db文件应该放在哪里?我需要读取和写入 tblStore db 文件。3. “用户沙箱”和“文档目录”有什么区别?

这是我目前拥有的:

-(IBAction)setInput:(id)sender
{
    NSString *strStoreNumber;
    NSString *strRegNumber;
    NSString *tableName = @"tblStore";
    NSString *dbStrStore = @"strStore";
    NSString *dbStrReg = @"strReg";


    strStoreNumber = StoreNumber.text;
    strRegNumber = RegNumber.text;

    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* documentsDirectory = [paths lastObject];
    NSString* databasePath = [documentsDirectory stringByAppendingPathComponent:@"tblStore.sqlite"];
//  NSString* databasePath = [[NSBundle mainBundle] pathForResource:@"tblStore" ofType:@"sqlite"];

    if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) 
    {
        NSLog(@"Opened sqlite database at %@", databasePath);

        char *err; 
        NSString *sql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS '%@' ('%@' TEXT PRIMARY KEY, '%@' TEXT);", tableName, dbStrStore, dbStrReg];
        if (sqlite3_exec(database, [sql UTF8String], NULL, NULL, &err) != SQLITE_OK) 
        { 
            sqlite3_close(database);
            NSAssert(0, @"Table failed to create.");
        }
        //...stuff
    } 
    else 
    {
        NSLog(@"Failed to open database at %@ with error %s", databasePath, sqlite3_errmsg(database));
        sqlite3_close (database);
    }

    NSString *querystring;

    // create your statement
    querystring = [NSString stringWithFormat:@"SELECT strStore, strReg FROM tblStore WHERE strStore = %@ AND strReg = %@;", strStoreNumber, strRegNumber];  

    const char *sql = [querystring UTF8String];

    NSString *szStore = nil;
    NSString *szReg = nil;

    sqlite3_stmt *statement = nil;
    if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL)!=SQLITE_OK) //queryString = Statement
    {
        NSLog(@"sql problem occured with: %s", sql);
        NSLog(@"%s", sqlite3_errmsg(database));
    }
    else
    {
        // you could handle multiple rows here
        while (sqlite3_step(statement) == SQLITE_ROW) 
        {            
            szStore = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)];
            szReg = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)];
        }        
    }

    sqlite3_finalize(statement);

    lblStoreNumber.text = szStore;
    lblRegNumber.text = szReg;   
} 

当我运行我的应用程序时,我收到以下错误:

2012-05-10 14:58:38.169 CCoDBTry[355:f803] Opened sqlite database at /Users/Matt****/Library/Application Support/iPhone Simulator/5.1/Applications/5DB7A218-A0F6-   485F-B366-91FD2F9BC062/Documents/tblStore.sqlite
2012-05-10 14:58:38.307 CCoDBTry[355:f803] sql problem occured with: SELECT strStore, strReg FROM tblStore WHERE strStore = 8053 AND strReg = 4;
2012-05-10 14:58:38.308 CCoDBTry[355:f803] no such column: strStore

我感谢任何抽出时间来解释其中一些内容的人,因为我很新,并且在完成我尝试过的一些事情方面没有成功。非常感谢你的帮忙!

4

7 回答 7

12

// 创建数据库

-(NSString *) filePath
{
 NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
 NSString *documentDirectory=[paths objectAtIndex:0];
 return [documentDirectory stringByAppendingPathComponent:@"LoginDatabase.sql"];
}

// 打开数据库

-(void)openDB
{
 if(sqlite3_open([[self filePath]UTF8String], &db) !=SQLITE_OK)
 {
   sqlite3_close(db);
   NSAssert(0, @"Database failed to Open");
 }
}

// 创建表

-(void) createTableNamed:(NSString*)tableName withField1:(NSString*) field1 withField2:(NSString*) field2

{
   char *err;
   NSString *sql=[NSString stringWithFormat:@" CREATE TABLE IF NOT EXISTS '%@'('%@' TEXT PRIMARY KEY,'%@' TEXT);",tableName,field1,field2];

   if(sqlite3_exec(db, [sql UTF8String], NULL, NULL, &err) !=SQLITE_OK)
   {
    sqlite3_close(db);
    NSAssert(0, @"Table failed to create");
   }
}

// 插入记录

-(void)insertrecordIntoTable:(NSString*) tableName withField1:(NSString*) field1 field1Value:(NSString*)field1Vaue andField2:(NSString*)field2 field2Value:(NSString*)field2Value
{

  NSString *sqlStr=[NSString stringWithFormat:@"INSERT INTO '%@'('%@','%@')VALUES(?,?)",tableName,field1,field2];
 const char *sql=[sqlStr UTF8String];

 sqlite3_stmt *statement1;

 if(sqlite3_prepare_v2(db, sql, -1, &statement1, nil)==SQLITE_OK)
 {
  sqlite3_bind_text(statement1, 1, [field1Vaue UTF8String], -1, nil);
  sqlite3_bind_text(statement1, 2, [field2Value UTF8String], -1, nil);
 }
 if(sqlite3_step(statement1) !=SQLITE_DONE)
    NSAssert(0, @"Error upadating table");
 sqlite3_finalize(statement1);
}

// 从表中检索数据

-(void)getAllRowsFromTableNamed:(NSString *)tableName
{
  NSString *field1Str,*field2Str;

  NSString *qsql=[NSString stringWithFormat:@"SELECT * FROM %@",tableName];
  sqlite3_stmt *statement;
  if(sqlite3_prepare_v2(db, [qsql UTF8String], -1, &statement, nil)==SQLITE_OK)
  {
   while(sqlite3_step(statement) ==SQLITE_ROW)
   {
     char *field1=(char *) sqlite3_column_text(statement, 0);
     char *field2=(char *) sqlite3_column_text(statement, 1);

     field1Str=[[NSString alloc]initWithUTF8String:field1];
     field2Str=[[NSString alloc] initWithUTF8String:field2];

     NSString *str=[NSString stringWithFormat:@"%@ - %@",field1Str,field2Str];
     NSLog(@"%@",str);
   }
}

}

在 viewDidLoad 调用方法

- (void)viewDidLoad
{

  [self openDB];
  [self createTableNamed:@"Login" withField1:@"USERNAME" withField2:@"PASSWORD"];
  [self insertrecordIntoTable:@"Login" withField1:@"USERNAME" field1Value:username andField2:@"PASSWORD" field2Value:password];

}

其中用户名和密码是 NSString 值;

于 2012-08-03T12:04:27.693 回答
2

如果你不知道自己在做什么,sqlite 会很痛苦。我在使用 sqlite c 函数时也遇到了一些问题,但后来我决定使用 sqlite 包装器。

FMDBBWDB是用于目标 c 的良好且易于使用的 sqlite 包装器。我建议你使用其中之一。

请注意,BWDB 在 lynda.com 教程(这个)中,如果您在网络上找不到它......请发表评论,我会将其上传到某个地方。

编辑:你可以在你的应用程序中写东西的唯一地方是你的文档目录......所以..它是简单的术语......如果数据库不在你的文档目录中..是只读的..也是..当您读/写到您的数据库..操作系统将数据库复制到文档目录中..并在那里进行所有读取和写入,因此您可以在应用程序包中拥有一个数据库,但您不能编辑那个...所以你最终会得到 2 db。我自己也有同样的问题。我在更新应用程序时通过合并 2 db 来修复它

edit2:我上传了 BWDB 最终项目(你有你的包装器和项目,看看它是如何工作的)

于 2012-05-10T19:30:10.900 回答
2

您可以使用以下代码获取在 Documents 文件夹中创建的数据库。只需在文档文件夹中传递一个路径,如果需要,该函数将在给定路径的文档文件夹中复制 sqlite 数据库。然后,您可以使用此路径来创建和查询数据库表。

+ (NSString*) createDatabaseIfRequiredAtPath:(NSString*)databasePath {

    if (databasePath == nil)
       return nil;


   NSString *path = [NSString stringWithFormat:@"%@/%@", databasePath, kMainDBName];
   NSFileManager *fileManager = [NSFileManager defaultManager];
   NSError *error = nil;

   if ([fileManager fileExistsAtPath:path] == NO) 
   {
    // The writable database does not exist, so copy the default to the appropriate location.
      NSString *defaultDBPath = [[NSBundle mainBundle] pathForResource:kMainDBName
                                                              ofType:nil];
      BOOL success = [fileManager copyItemAtPath:defaultDBPath 
                                       toPath:path
                                        error:&error];
      if (!success)
      {
        NSCAssert1(0, @"Failed to create writable database file with message '%@'.", [  error localizedDescription]);
        return nil;
    }
}

return path;
于 2012-05-10T19:50:08.533 回答
0

您可以打开终端并 cd 到 /Users/Matt* * /Library/Application Support/iPhone Simulator/5.1/Applications/5DB7A218-A0F6-485F-B366-91FD2F9BC062/Documents/

然后 sqlite3 tblStore.sqlite

然后使用 .schema tblStore 应该显示您的表模式,您可以查看它是否正确构建。

您的数据库需要位于文档目录中才能进行写访问。如果您的数据库只是被读取,从不写入它可能在您的应用程序包中。完成此操作的一种方法是创建您的 database.sqlite 文件并将其添加到包中,然后在启动时将其复制到文档目录(如果它不存在)。

于 2012-05-10T19:34:02.017 回答
0

您是否有特定的原因想要直接使用 SQLLite,而不是使用 CoreData?CoreData 使用 SQLLite 数据库,但它本身是一个更高级别的 API,特别是对于表视图等,您可以获得许多 Xcode 中已经为其设置的功能和模板方法。定义数据模型是微不足道的,你会得到大量的样板代码,而且都经过优化。

http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started

CoreData 有时被描述为具有陡峭的学习曲线。我不同意。如果您正在考虑自己在应用程序中编写 SQL,那么使用 CoreData 不会有任何问题。

术语“沙盒”是您的应用程序具有读/写访问权限的设备文件系统部分的抽象术语。“文档”目录是应用程序沙箱中的特定目录。沙箱中除了文档目录之外还有其他文件,但大多数在 iOS 中将数据保存到文件系统的应用程序都是在文档目录中进行的。

于 2012-05-10T19:34:23.053 回答
0

也许你忘记了表格插入。创建了数据库和表,但它的空表。您试图从空表中读取记录。

于 2013-06-06T19:38:13.243 回答
0

我试过上面的方法对我不起作用,主要是因为给出的示例通常指向数据库文件,但并没有真正创建它。

在观察 sqlite3 如何使用命令 shell 工作时,我是这样解决问题的:

  1. (出于测试目的),要使用 Linux shell 创建文件,请执行以下操作:

sqlite3 Heider.db

这创建了一个新的数据库文件名 (Heider.db),还启动了 DB 命令提示符以创建 SQL 查询,... 在执行任何查询之前,只需输入以下内容,无需执行任何操作即可存在:

。出口

在 Linux shell 检查创建的文件,执行:

ls -ltra

您应该看到创建了一个大小为 0 字节的“Heider.db”文件,这意味着 sqllite3 工具正在创建一个没有内容的空白文件。

现在,要检查这是否可行,请返回 sqlite:

sqlite3 Heider.db

现在,使用以下命令创建一个新表:

创建表测试(id int not null 主键);

插入一些东西:

插入 test(id) 值(123);

请注意,查询执行得很好,没有任何错误。

现在,退出并检查:

.exit ls -ltra

该文件中应该有一些数据,这证实了 Linux 中的工具至少可以工作......

现在,离开 Linux/Shell 并回到 XCODE/Development(或您正在开发的任何工具)......这使我们的生活变得如此简单,因为我们需要做的就是使用代码“以某种方式”手动创建文件, 然后让 sqlite 使用它。

因此,这是您需要做的:

// 检查文件名是否已经存在:

DBFileName = @"MyNewFile.db";  

if (![[NSFileManager defaultManager] fileExistsAtPath: DBFileName])
{

    NSLog([NSString stringWithFormat:@"Database does not exists, creating: %@", DBFileName]);
    [[NSFileManager defaultManager] createFileAtPath:DBFileName contents:NULL attributes:NULL];  
}

// Use SQLite to access the new file to do whatever you want:

int DBOpen = sqlite3_open([_DBFileName UTF8String], &_SqlLite);

if (DBOpen == SQLITE_OK) 
{

    NSLog([NSString stringWithFormat: @"Client: SQLite DB Opended Successfully, creating test table..."]); 

// Heider: Notice I am using "self" here because I am having this as a
wrapper class (see at the bottom of this post the whole function), you don't have to do the same, as you can use your own
SQLITE3 object directly instead...

 [self ExecQuery:@"create table Test(id int not null primary key);"];
 [self ExecQuery:@"insert into Test(id) values (123);"];

}

如果您需要,我在上面使用的 SELF ExecQuery 也在下面:

-(BOOL)ExecQuery:(NSString *)Query { BOOL 成功 = NO;

if (sqlite3_prepare_v2(_SqlDB, [Query UTF8String], -1, &_SqlQuery, NULL) == SQLITE_OK)
{
    if (sqlite3_step(_SqlQuery) == SQLITE_DONE)
    {
        NSLog([NSString stringWithFormat: @"Client: SQL Query Successful: %@", Query]);
    } else {
        NSLog([NSString stringWithFormat: @"Client-Error Executing SQL Query: %@", Query]);
    }
} else {
    Log(3, [NSString stringWithFormat: @"Client-Error Preparing SQL Query: %@", Query]);
}

sqlite3_finalize(_SqlQuery);

return Successful;

}

该过程是创建一个您喜欢的空白文件,然后将 sqlite3 指向它,然后以旧的方式执行您的 SQL ......应该很简单。

祝你好运,我希望这会有所帮助。

H

于 2021-01-11T09:27:27.297 回答