Как вытащить запись из БД и поместить ее в переменную? Sqlite3 c++

Подскажите как правильнее будет сделать, потому что я SQL только начал активно юзать и в написании запросов не очень силен. Я понял как выводить всю таблицу или отдельные ее записи, но мне нужно как то вытаскивать запись и класть ее в переменную, чтобы уже работать непосредственно с этими данными.

Тут я писал запросы, которые возвращают записи или таблицу

static int selectData(const char* s)

{

sqlite3* DB;
char* messageError;

string sql = "SELECT * FROM Users;";

int exit = sqlite3_open(s, &DB);
exit = sqlite3_exec(DB, sql.c_str(), callback, NULL, &messageError);

if (exit != SQLITE_OK) {
    cerr << "Error in selectData function." << endl;
    sqlite3_free(messageError);
}
else
    cout << "Records selected Successfully!" << endl;

return 0;

}

таблицу и записи я выводил в консоль вот таким образом

 static int callback(void* NotUsed, int argc, char** argv, char** azColName)

{

for (int i = 0; i < argc; i++) 

{
   cout << azColName[i] << ": " << argv[i] << endl;
}
cout << endl;

return 0;

}


Ответы (1 шт):

Автор решения: needKVAS

Через exec/callback

Если Вы хотите использовать callback функцию, то в её первый аргумент void* передаётся четвёртый аргумент функции sqlite3_exec.

Допустим, мы хотим получить пароль на основе логина. Мой запрос выглядит так:

SELECT `Password` FROM `Users` WHERE `Login` = 'test';

Тогда моя callback функция, которая должна записать мне значения пароля в std::string, будет выглядеть примерно так:

static int callback(void *pString, int argc, char **argv, char **azColName){
    if (argc>0) {
        std::string* str = static_cast<std::string*>(pString);
        str->assign(argv[0]);
    }
    return 0;
}

Здесь я исхожу из того, что знаю индекс искомого столбца (это 0). В зависимости от ситуации можно обрабатывать элементы другим образом.

В коде это будет использоваться так:

std::string sql1("SELECT `Password` FROM `Users` WHERE `Login` = 'test';");
std::string outStr;
result = sqlite3_exec(db, sql1.c_str(), callback, &outStr, &err);
if (result != SQLITE_OK) {
    std::cerr << "Error in selectData function." << endl;
    sqlite3_free(err);
}
std::cout << "Result:" << outStr << std::endl;

Важно понимать, что функция callback будет вызываться для каждой строки результата, что необходимо учесть при работе с первым аргументом.

Через подготовленные выражения

В большинстве случаев более выгодно использовать подготовленные выражения.

В запросе заменим искомую строку на выражение формата ?NNN, на место которого мы будем подставлять переменную:

SELECT `Password` FROM `Users` WHERE `Login` = ?1;

Переменная pStmt будет хранить указатель на подготовленное выражение sqlite3_stmt*, которое создастся в функции sqlite3_prepare_v2.

Функция sqlite3_bind_text свяжет выражение ?1 с подаваемым ему на вход объектом (в данном случае InpLogin.c_str()). Смотрите ответ на Ваш вопрос или документацию.

Функция sqlite3_step будет возвращать SQLITE_ROW, в случае если возможно получить ещё одну строку из ответа. Т.к. строк может больше одной обрабатываем их в цикле.

Функции группы sqlite3_column_* позволяют получать значения колонки в строке результата на основе подготовленного выражения. В данном случае используем sqlite3_column_text (Она возвращает const unsigned char* поэтому используем reinterpret_cast).

Завершаем работу с подготовленным выражением используя sqlite3_finalize.

std::string InpLogin = "test";
sqlite3_stmt* pStmt = nullptr;
std::string sql2("SELECT `Password` FROM `Users` WHERE `Login` = ?1;");
result = sqlite3_prepare_v2(db, sql2.c_str(), -1, &pStmt, nullptr);
if (result != SQLITE_OK) {
     std::cerr  << "Prepare error\n";
    return -1;
}
result = sqlite3_bind_text(pStmt, 1 /*?1*/, InpLogin.c_str(), -1, SQLITE_TRANSIENT);
if (result != SQLITE_OK) {
    std::cerr  << "Bind text error\n";
}
while (true) {
    result = sqlite3_step(pStmt);
    if (result == SQLITE_ROW) {
        outStr.assign(reinterpret_cast<const char*>(sqlite3_column_text(pStmt, 0)));
        //Работаем со строкой
        std::cout << "Result:" << outStr << std::endl;
    } else {
        break;
    }
}
if ( result != SQLITE_DONE ) {
    std::cerr  << "Execution error\n";
}
sqlite3_finalize(pStmt);

Касательно запроса

Вероятно в Вашем случае следует использовать другой запрос, который сравнил бы значения переменных на стороне БД:

SELECT `Users` FROM `Users` WHERE `Login` = ?1 AND `Password` = ?2;

В случае если он ничего не вернёт, то искомого пользователя с такой парой Login/Password не существует. С аналогичной целью можно запросить количество пользователей с искомой парой Login/Password:

SELECT COUNT(*) FROM `Users` WHERE `Login` = ?1 AND `Password` = ?2;
→ Ссылка