Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt: Save result of SQL-query in variable, use C++ variable in SQL-query

Tags:

c++

mysql

qt

My project is to program a simple ShopApp. One function is about checking, whether there is enough stock left, so that a customer can buy the desired amount of whatever he wants to buy. The functions looks like (where cart is a std::vector<product> and Pid stands for product id):

bool sqlfunctions::checkStock(){
    QSqlQuery query;
    int diff, stock;
    for(iter cursor = cart.begin();cursor!=cart.end();cursor++){
        query.prepare("SELECT stock FROM products WHERE id = cursor->getPid()");
        query.exec();
        // Need to save result of query into variable stock
        stock = ??;
        diff = stock - cursor->getAmount;
        if(diff < 0){
            return false;
        }
    }
    return true;
}

Obviously this function is not functional, because cursor->getPid() is not executed since it is a string. So the question here is how to insert a c++-variable into the sql-query?In regular C++ i would used some swprintf_s function. So is query.prepare(swprintf_s(...)) a good idea?

The second thing is, since both query.exec() and query.prepare() are booleans, which return true or false, depeding on success, how can i store results of the queries in a c++ variable?

Please note, that I am new to SQL and SQL with Qt. I use QT5. I already tried to read the documentation about theQSqlQuery class and its functions, BindValue() and addBindValue() seem to be interesting. However i dont really understand how they work.

Edit

So now I've got a minimal example here that does not work yet, despite following the accepted answer. However the compiler does not give me any warnings or errors:

void MainWindow::on_ButtonSQL_clicked()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("...");
    db.setDatabaseName("...");
    db.setUserName("...");
    db.setPassword("...");
    db.setPort(3306);
    db.open();

    QMessageBox msgBox;

    if (db.open()) {
        msgBox.setText("It works :)");
        msgBox.exec();
    }
    else {
        msgBox.setText("No connection.");
        msgBox.exec();
    }

    QSqlQuery query(db);

    //  This query worked!
    query.exec("INSERT INTO users (id, username, balance) VALUES(25, 'someName', 10000)");       

    // initialize someNumber to check later, whether it was processed correctly.
    int id = 2, someNumber = 20;
    query.prepare("SELECT stock FROM products WHERE id = :myid");
    query.bindValue(":myid", id);
    query.exec();

    QString idValue = query.boundValue(0).toString();

    someNumber = query.value(0).toInt();
    msgBox.setText("The stock is: "+QString::number(someNumber)+"\nThe placeholder has the value: "+idValue);
    msgBox.exec();
}

Expected msgBox of the last msgBox is:

The stock is: 100 
The placeholder value is: 2

Output actually is:

The stock is: 0
The placeholder value is: 2

If I instead try to select a string (e.g. productName), say with QString myProductName = query.value(0).toString() (and respective changes in the code), the return would be an empty string.

** SOLVED: ** See comment from Floris in the accepted answer. I missed query.next().

like image 314
Alex Avatar asked May 10 '15 08:05

Alex


1 Answers

It is pretty straight forward actually:

QSqlQuery query;
query.prepare("Select stock from products where id = :input");
query.bindValue(":input", cursor->getPid());
query.exec();

You bind the values to the argument in the string. Arguments follow the format: :name. There is also positional binding which binds in the order it sees ?.

QSqlQuery query;
query.prepare("Select stock from products where id = ?");
// No need for an identifier
query.bindValue(cursor->getPid());
query.exec();

To iterate the records you obtained from a query you can do the following:

QSqlQuery query;
query.prepare("SELECT stock FROM employee WHERE id = ?");
query.bindValue(cursor->getPid());
query.exec();

if (query.next()) {
    int stock = query.value(0).toInt();
    // You could store the information you obtain here in a vector or something
}

You could also put the prepare statement outside the for loop. If you are interested in iterating multiple records (from a select statement) you can replace the if statement with a while statement.

Concerning QSqlQuery::next():

Retrieves the next record in the result, if available, and positions the query on the retrieved record. Note that the result must be in the active state and isSelect() must return true before calling this function or it will do nothing and return false.

As taken from QSqlQuery. You will need to make this call before the record will actually be accessible with .value(int).

like image 192
Floris Velleman Avatar answered Nov 03 '22 07:11

Floris Velleman