我有一个接受3个参数的函数,这些参数用于构造SQL查询,这些查询对我数据库中的各个表执行各种操作。我已经尝试转换当前代码,它只是在查询字符串中使用标准的NSString替换,但是在查看几个简单的导航后出现了问题。
这就是我之前所拥有的:
NSString *queryStrInsert = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)", tableName, columns, values];
这就是我现在所拥有的:
NSString *queryStrInsert = [NSString stringWithFormat:@"INSERT INTO ? (?) VALUES (?)"];
const char *sqlInsert = [queryStrInsert UTF8String];
if ((sqlite3_open([[self filePath] UTF8String], &congressDB)==SQLITE_OK))
{
if (sqlite3_prepare_v2(congressDB, sqlInsert, -1, &stmtInsert, NULL)==SQLITE_OK)
{
if(sqlite3_bind_text(stmtInsert, 0, [tableName UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
{
NSLog(@"Binding 0 did not work");
}
if(sqlite3_bind_text(stmtInsert, 1, [columns UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
{
NSLog(@"Binding 1 did not work");
}
if(sqlite3_bind_text(stmtInsert, 2, [values UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
{
NSLog(@"Binding 2 did not work");
}
}
}
我的代码在sqlite3_prepare_v2(也尝试过sqlite3_prepare)时遇到问题:
near "?": syntax error
3个绑定语句永远不会触发。我已尝试在准备之上移动,但SLITE_OK也为每个返回false。
之前的代码工作正常(没有参数化查询)但希望它更安全并处理撇号等。
感谢。
编辑:
似乎问题的一部分是表和列名称不能只参数值才能参数化。
更新的代码:
NSString *queryStrInsert = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (?)", tableName, columns];
[self openDB];
const char *sqlInsert = [queryStrInsert UTF8String];
if ((sqlite3_open([[self filePath] UTF8String], &congressDB)==SQLITE_OK))
{
if (sqlite3_prepare_v2(congressDB, sqlInsert, -1, &stmtInsert, NULL)==SQLITE_OK)
{
if(sqlite3_bind_text(stmtInsert, 1, [values UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK)
{
NSLog(@"Binding 2 did not work");
} else {
NSLog(@"Binding 2 worked - ,%@", stmtInsert);
}
}
}
现在出现错误:
1 values for 6 columns
我认为我在这里有一个更大的问题,我试图在这里生成相当动态的SQL查询,而不是有很多很多静态插入查询。您可以从我的原始代码中看到,我正在尝试构建一个灵活的查询,该查询可以根据运行查询的表来获取不同数量的列/值。我已经有效地为列列表及其值创建了一个变量字符串,但我现在很确定这种方法不适用于参数。例如,在这种情况下,值的参数是:
'8ffed886-5f7c-e311-a863-000c29beef51','','','','1389623548','Rick Sanchez'
AS参数化后,整个字符串被视为一个值。不要以为有一个很好的方式来做我在这里尝试的东西吗?如果不是,我将不得不恢复到原来的方法,只是执行一个基本的NSString替换为'是'等...
答案 0 :(得分:3)
if ((sqlite3_open([[self filePath] UTF8String], &congressDB) == SQLITE_OK)) {
if (sqlite3_prepare_v2(congressDB, sqlInsert, -1, &stmtInsert, NULL) == SQLITE_OK) {
if (sqlite3_bind_text(stmtInsert, 1, [tableName UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
NSLog(@"Binding 1 did not work");
}
if (sqlite3_bind_text(stmtInsert, 2, [columns UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
NSLog(@"Binding 2 did not work");
}
if (sqlite3_bind_text(stmtInsert, 3, [values UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) {
NSLog(@"Binding 3 did not work");
}
}
}
一:您无法参数化表名或列,只能参数值。
二:从1
答案 1 :(得分:0)
所以你要插入表名,表列名和值,接下来是我接近它的方法:
-(void)insertSpecial:(NSString *)tblNm colNames:(NSArray *)colNms colVals:(NSArray *)colVls{
sqlite3 *database;
if(sqlite3_open([pathToYourDbHere UTF8String], &database) == SQLITE_OK) {
NSString *cols=@"";
NSString *vals=@"";
for(int i=0;i<colNms.count;i++){
cols=[cols stringByAppendingString:[colNms objectAtIndex:i]];
vals=[vals stringByAppendingString:@"?"];
if(i<colNms.count-1) {
vals=[vals stringByAppendingString:@","];
cols=[cols stringByAppendingString:@","];
}
}
const char *sqlStatement3=[[NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES(%@)",tblNm,cols,vals] UTF8String];
sqlite3_stmt *compiledStatement3;
if(sqlite3_prepare_v2(database, sqlStatement3, -1, &compiledStatement3, NULL) == SQLITE_OK) {
for (int i=0; i<colVls.count; i++) {
sqlite3_bind_text(compiledStatement3, i+1, [[colVls objectAtIndex:i] UTF8String], -1, SQLITE_TRANSIENT);
}
if(sqlite3_step(compiledStatement3) != SQLITE_DONE ) {
NSLog( @"Error: ins records %s", sqlite3_errmsg(database) );
}else{
NSLog( @"Insert into records row id = %lld", sqlite3_last_insert_rowid(database));
}
}
sqlite3_finalize(compiledStatement3);
}
sqlite3_close(database);
database =nil;
}