Как получить строки в базе данных sqlite3 с помощью подготовленных операторов с использованием времени даты («сейчас», «-1 день»)?

#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);