我正在尝试在运行时通过Objective-C创建一个SQLite3数据库文件。 我正在尝试创建一个名为"tblStore"的表。 我希望字段名称称为"strStoreNumber"和"strStoreReg"。 我是iOS和SQLite的新手,所以我很难找到执行此操作的语法。 除了创建表之外,我还希望创建的表不驻留在应用程序包中,而是驻留在/存储在手机上的某个地方。 表需要可读/可写。 我已经阅读了一些关于"用户沙箱"和"文档目录"的阅读。 我不确定我是否理解两者之间的区别。 理想情况下,我的应用将使用按钮从文本字段获取输入。 将文本字段的输入放入字符串后,将进行检查以查看我的"tblStore"SQLite 表是否存在,如果不存在,则将创建该表。
回顾一下:1. Obj-C/SQLite创建一个名为"tblStore"的表的语法是什么,其中包含"strStoreNumber"和"strStoreReg"字段?2. 数据库文件应驻留在哪里? 我需要读取和写入 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
我很感激任何花时间解释这些东西的人,因为我是新手,并且没有成功地完成我尝试过的一些事情。非常感谢您的帮助!
//创建数据库
-(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);
}
}
}
在视图中DidLoad 调用方法
- (void)viewDidLoad
{
[self openDB];
[self createTableNamed:@"Login" withField1:@"USERNAME" withField2:@"PASSWORD"];
[self insertrecordIntoTable:@"Login" withField1:@"USERNAME" field1Value:username andField2:@"PASSWORD" field2Value:password];
}
其中用户名和密码是 NS 值;
如果你不知道自己在做什么,sqlite 会很痛苦。我在 sqlite c 函数方面也遇到了一些问题,但后来我决定使用 sqlite 包装器。
FMDB 和 BWDB 是很好的,易于使用的 sqlite 包装器,用于目标 c。我建议你使用其中之一.
请注意,BWDB 在 lynda.com 教程(这个(中,如果您在网络上找不到它......发表评论,我会将其上传到某个地方。
编辑:您可以在应用程序中编写内容的唯一位置是文档目录中...所以。。简单来说...如果数据库不在您的文档目录中。是只读的。.也。。当您读取/写入数据库时。操作系统复制文档目录中的数据库。并在那里进行所有读取和写入,因此您可以在应用程序包中拥有一个数据库,但您无法编辑该数据库......所以你最终会得到 2 dB。我自己也有同样的问题..当我更新应用程序时,我通过合并 2 dB 来修复它
edit2:我上传了BWDB最终项目(你在那里有你的包装器和项目看看它是如何工作的(
可以使用以下代码获取在"文档"文件夹中创建的数据库。只需在文档文件夹中传递一个路径,如果需要,该函数将在给定路径处复制文档文件夹中的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;
是否有特定原因想要直接使用 SQLLite,而不是使用 CoreData?CoreData使用SQLLite数据库,但本身是一个更高级别的API,特别是对于表视图等,您可以获得许多已经在Xcode中为其设置的功能和模板方法。定义数据模型是微不足道的,你会得到大量的样板代码,而且这一切都得到了优化。
http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started
CoreData有时被描述为具有陡峭的学习曲线。我不同意。如果您正在考虑自己在应用程序中编写SQL,那么使用CoreData不会遇到任何问题。
术语"沙盒"是应用程序具有读/写访问权限的设备文件系统部分的抽象术语。"文档"目录是应用程序沙箱中的特定目录。除了文档目录之外,沙盒中还有其他文件,但大多数将数据保存到 iOS 文件系统的应用程序都是在文档目录中保存的。
您可以打开终端和CD到/用户/Matt**/图书馆/应用程序支持/iPhone模拟器/5.1/应用程序/5DB7A218-A0F6-485F-B366-91FD2F9BC062/文档/
then sqlite3 tblStore.sqlite
然后使用 .schema tblStore 应该显示您的表架构,您可以查看它是否正确构建。
您的数据库需要位于文档目录中才能进行写入访问。如果您的数据库只被读取,则永远不会写入它可能会在您的应用程序捆绑包中。实现此目的的一种方法是创建 database.sqlite 文件并将其添加到捆绑包中,并在启动时将其复制到文档目录(如果那里尚不存在(。
也许你忘记了表格插入。创建了数据库和表,但其表为空。 您尝试从空表中读取记录。
我尝试了上述方法对我不起作用,主要是因为给出的示例通常指向数据库文件,但不会真正创建它。
在观察 sqlite3 如何使用命令外壳工作后,以下是我解决问题的方法:
- (出于测试目的(,要使用 Linux shell 创建文件,请执行以下操作:
sqlite3 海德.db
这创建了一个新的数据库文件名(Heider.db(,还启动数据库命令提示符以创建SQL查询,...在执行任何查询之前,只需通过输入以下内容而不执行任何操作:
。退出
在 Linux shell 中检查创建的文件,执行以下操作:
ls -ltra
您应该看到有一个大小为 0 字节的"Heider.db"文件,这意味着 sqllite3 工具正在创建一个没有内容的空白文件。
现在,要检查这是否有效,请返回 sqlite:
sqlite3 海德.db
现在这一次,使用以下方法创建一个新表:
创建表测试(ID int 不为空的主键(;
插入一些内容:
插入测试(ID(值(123(;
请注意,查询执行得很好,没有任何错误。
现在,退出并检查:
。退出ls -ltra
该文件中应该有一些数据,这确认了 Linux 中的工具至少可以工作......
现在,离开 Linux/Shell,回到 XCODE/开发(或你正在使用的任何工具(......这使我们的生活变得如此简单,因为我们需要做的就是使用代码"以某种方式"手动创建一个文件,然后让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's ExecQuery 也在下面,以防您需要它:
-(BOOL(ExecQuery:(NSString *(查询 {布尔成功 = 否;
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