Делаем позицию параметра в командах sqlite3_bind динамической

В проекте мне не разрешено использовать сторонний код (например, GRDB, Swift.sqlite), поэтому мне нужно напрямую использовать функции sqlite3 c-wrapper Swift.

Мой оператор 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.

Кажется неправильным «жестко закодировать» положение привязок. Есть ли способ решить эту проблему без жесткого кодирования этих позиций?

Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел &quot;Заголовок&quot; в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
1
0
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Жестко закодированные числовые индексы так же жестко закодированы, как и сама необработанная строка SQL - не лучше, но и не хуже. Я бы не слишком беспокоился о них. 1, 2, 3? ОК: это первый, второй и третий параметр - это понятно.

Я согласен с тем, что мы могли бы улучшить ваш пример кода, если бы потребность в nextPosition исчезла. Я перечисляю несколько вариантов ниже.


Одним из возможных улучшений является перемещение теста flagC в конец при построении SQL-запроса:

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 "

Вместо того, чтобы указывать числовые индексы для ваших параметров (1, 2, 3, nextPosition), вы должны использовать sqlite3_bind_parameter_index, чтобы превратить имена параметров (:a, :minB и т. д.) в индексы.


Наконец, еще один подход полностью состоит в том, чтобы заранее протестировать flagC и полностью независимо обрабатывать оба SQL-запроса. Это устранит вашу потребность в nextPosition.

У меня довольно много случаев, подобных примеру flagC, поэтому перемещение в конец не очень помогает. Но использование sqlite3_bind_parameter_index отлично решило бы мою проблему. Спасибо - и я обычно использую GRDB - и мне это нравится. 🤣 Выполнение этого проекта "вручную" действительно дало мне дополнительную оценку! Спасибо за создание этой замечательной библиотеки.

Joseph 17.01.2023 07:47

Спасибо, Джозеф :-) Счастливый SQLite - это многословно, но все же ваш друг!

Gwendal Roué 17.01.2023 09:39

Другие вопросы по теме