#c #sqlite #prepared-statement
Вопрос:
Учитывая таблицу, разработанную таким образом:
CREATE TABLE calls(timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, callerid TEXT, contactid INTEGER)
Если я хочу извлечь все строки, в которых метка времени находится в течение 1 дня, я могу использовать этот sql:
SELECT * FROM calls WHERE timestamp >= datetime('now', '-1 day');
В коде, использующем небезопасные удобные функции, я мог бы написать это так:
sqlite3 *db;
char *err_msg = 0;
int rc = sqlite3_open("mydb.db", amp;db);
const char* sql = "SELECT * FROM calls WHERE timestamp >= datetime('now', '-1 day');";
rc = sqlite3_exec(db, sql, callback, 0, amp;err_msg);
Конечно, мне пришлось бы настроить функцию обратного вызова, чтобы обрабатывать извлечение записей.
Но если бы вместо этого я хотел выполнить ту же инструкцию SELECT, используя подготовленную инструкцию, как бы я это сделал?
Я пытался вот так:
sqlite3 *db;
char *err_msg = 0;
int rc = sqlite3_open("mydb.db", amp;db);
sqlite3_stmt *stmt = NULL;
const char* sql = "SELECT rowid,* FROM calls WHERE timestamp >= :timestamp;";
rc = sqlite3_prepare_v2(db, sql, -1, amp;stmt, NULL);
int idx = sqlite3_bind_parameter_index(stmt, ":timestamp");
rc = sqlite3_bind_text(stmt, idx, "datetime('now', '-1 day')", -1, SQLITE_STATIC); break;
// but this while loop exits immediately - ie no data returned
while ((rc = sqlite3_step(stmt)) != SQLITE_DONE) {
// code here to extract field data
}
rc = sqlite3_finalize(stmt);
Но sqlite3_step немедленно возвращает значение SQLITE_DONE, т. е. не возвращает никаких данных.
Как я должен настроить вызовы функций подготовленного оператора, чтобы это сработало.
Ответ №1:
Используйте оператор объединения SQLite ||
, чтобы объединить именованный параметр :days
, который будет строкой, как "-1"
в инструкции sql:
const char* sql = "SELECT rowid, * FROM calls WHERE timestamp >= datetime('now', :days || ' day');";
rc = sqlite3_prepare_v2(db, sql, -1, amp;stmt, NULL);
int idx = sqlite3_bind_parameter_index(stmt, ":days");
rc = sqlite3_bind_text(stmt, idx, "-1", -1, SQLITE_STATIC);
Или если вы хотите передать строку, например "-1 day"
, с именованным параметром :period
:
const char* sql = "SELECT rowid, * FROM calls WHERE timestamp >= datetime('now', :period);";
rc = sqlite3_prepare_v2(db, sql, -1, amp;stmt, NULL);
int idx = sqlite3_bind_parameter_index(stmt, ":period");
rc = sqlite3_bind_text(stmt, idx, "-1 day", -1, SQLITE_STATIC);