动态设置sqlite3_bind命令中的参数位置

wqsoz72f  于 2023-01-17  发布在  SQLite
关注(0)|答案(1)|浏览(175)

在这个项目中,我不允许使用第三方代码(即GRDB、Swift.sqlite),所以我需要直接使用swift的c- Package 器sqlite3函数。
我的SQL语句是可变的,基于某些标志。

var sql = "SELECT * FROM myTable WHERE "
sql += " colA = ? "
sql += " AND (colB > ? OR colB < ?)  "

if flagC == true {
  sql += " AND colC = ? "
}

sql += " AND colD = ? "

var stmt = OpaquePointer?

guard sqlite3_prepare_v2(dbPointer, sql, -1, &stmt, nil) == SQLITE_OK
else { print("error") }

guard sqlite3_bind_text(stmt, 1, (myVarA as NSString).utf8String, nil) == SQLITE_OK &&
      sqlite3_bind_double(stmt, 2, myVarB, nil) == SQLITE_OK &&
      sqlite3_bind_double(stmt, 3, myVarB1, nil) == SQLITE_OK 
else { print("error") }

var nextPosition = 4
if flagC == true {
  guard sqlite3_bind_int(stmt, nextPosition, myVarC, nil) == SQLITE_OK
  else { print("error") }
  nextPosition += 1
}

guard sqlite3_bind_double(stmt, nextPosition, myVarD, nil) == SQLITE_OK
else { print("error") }

while sqlite3_step(stmt) == SQLITE_ROW {
  // deal with result
}

这是可行的,但是由于要中断guard语句以容纳潜在的参数,因此感觉非常笨拙。
我能想到的使参数位置绑定“动态”的唯一方法是使用nextPosition帮助变量。
“硬编码”绑定的位置感觉不对,有没有办法不用硬编码这些位置就解决这个问题?

hlswsv35

hlswsv351#

硬编码的数字索引和原始SQL字符串一样硬编码--不是更好,但也不是更差。我不会太担心它们。1,2,3?好的:这是第一,第二和第三个参数,这很清楚
我同意,如果不再需要nextPosition,我们可以增强您的示例代码。
一个可能的改进是在构建SQL查询时将flagC测试移到末尾:

var sql = "SELECT * FROM myTable WHERE "
sql += " colA = ? "
sql += " AND (colB > ? OR colB < ?)  "
sql += " AND colD = ? "

if flagC == true {
  sql += " AND colC = ? "
}

您仍将使用硬编码索引(1,2,3,4),但不再需要nextPosition
另一种方法是使用命名参数:

var sql = "SELECT * FROM myTable WHERE "
sql += " colA = :a "
sql += " AND (colB > :minB OR colB < :maxB)  "

if flagC == true {
  sql += " AND colC = :c "
}

sql += " AND colD = :d "

您可以使用sqlite3_bind_parameter_index将参数名(:a:minB等)转换为索引,而不是为参数(1、2、3、nextPosition)提供数字索引。
最后,另一种方法是尽早测试flagC,并完全独立地处理两个SQL请求,这将消除对nextPosition的需求。

相关问题