在 iOS 应用程序中没有从 sqlite3 获取行
以下代码不返回任何行,但是当我在终端中的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我看到您已经接受了答案,但我想我在您的 sqlite 调用中看到了问题。
在终端中,我猜您正在执行类似这样的查询:
但是您的代码没有执行等效的查询。相反,它执行如下查询:
由于字符串“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:
But your code is not doing an equivalent query. It is instead doing a query like this:
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.
(添加此作为答案,因为将其作为评论会非常麻烦)
我强烈建议使用 FMDB 与数据库交互。它是 SQLite C API 的包装器,使与数据库的交互变得非常容易。您的代码可以更改为以极少的干预来使用它。它看起来是这样的:
这不是看起来更具可读性吗?很容易看出您正在执行查询,迭代结果,并拉出“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:
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 aFMDatabase*
as it's "database" instead of asqlite3*
. 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.