QSqlQuery.record() is always empty - c++

I'm editing the database in this manner:
QSqlQuery query;
query.prepare("UPDATE student "
"SET name = ? "
"WHERE id = ?");
QString name = "t";
int id = 3;
query.addBindValue(name);
query.addBindValue(id);
query.exec(); // query exec returns true
QSqlRecord record = query.record(); // but the record is empty!
mTableModel->beforeInsert(record);
The retrieved record is always empty, but the QSqlTableModel still changes! I need the record to be valid because I'm trying to synchronize an sql db with a std::vector.
I'm connecting to the database like this:
mDatabase = QSqlDatabase::addDatabase("QSQLITE");
mDatabase.setDatabaseName("database.db");
mDatabase.open();
I tried calling QSqlQuery::clear(), QSqlQuery::finish() but it didn't help. I also tried to open and close the DB, but it also didn't help. What can I do? :\

Qt is not a pain indeed.
All your code is good. The only wrong assumption is that an update request will automatically give you back the updated record. You have to make a new select request on this id to get the updates data in a QSqlRecord.
//[untested]
QSqlQuery select;
select.prepare("SELECT * from student where id = ?");
select.addBindValue(id);
if (select.exec() && select.next()) {
QSqlRecord record = select.record();
}

Related

QSqlQuery 'Parameter Count Mismatch'

I am trying to take data from six fields on a form and pass the data the user enters into a database (A local SQLite3 database). The ID is an integer and the primary key and the rest are varchars of enough length. After reading a lot of related questions, I still cannot figure out where my code is going wrong. I have confirmation that the program is connected to the database, but I keep getting 'parameter count mismatch'. Where am I going wrong? I'm using Qt 5.15 and C++. The table TOOL exists, as I have it open in SQLite Manager with a test row already inserted.
Below is the function that is supposed to submit the data:
//passes data to database upon clicking submit button
void Add_item::on_submitButton_clicked() {
QString name, location, safety, summary, uses, idNumber;
idNumber = ui->testIdBox->text();
name = ui->nameField->text();
location = ui->locationField->text();
safety = ui->safetyField->text();
summary = ui->summaryField->text();
uses = ui->useField->text();
QSqlQuery qry;
qry.prepare("INSERT INTO TOOLS (TOOL_ID, TOOL_NAME, TOOL_SUMMARY, TOOL_LOCATION, TOOL_USE, TOOL_SAFETY) "
"VALUES (:idNumber, :name, :summary, :location, :uses, :safety)");
//binding all values to prevent sql injection attacks
qry.bindValue(":idNumber", idNumber);
qry.bindValue(":name", name);
qry.bindValue(":summary", summary);
qry.bindValue(":location", location);
qry.bindValue(":uses", uses);
qry.bindValue(":safety", safety);
if(qry.exec()){
QMessageBox::critical(this,tr("Confirmation Message"),tr("Success!"));
}
else {
QMessageBox::critical(this,tr("Confirmation Message"),tr("Error, data was not saved."), qry.lastError().text());
}
connClose();
}
Here is where I connect to the database:
//connecting to database
bool Add_item::connOpen() {
QSqlDatabase mydb = QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("C:/Users/laesc/OneDrive/Documents/ToolBuddy/test.db");
if (mydb.open()) {
ui->statusLabel->setText("Connected!");
qDebug()<<("Connected");
return true;
}
else {
ui->statusLabel->setText("Connection Not Successful...");
qDebug()<<("Not Connected");
return false;
}
}
For future viewers, I ended up reducing the number of parameters to 2 and the query worked. For one reason or another the query didn't work if I tried to bind more than 2 variables. I'm just doing multiple queries.

QSqlQuery not working

So I have this problem basically, I cannot exec my QsqlQuery.
I am connected to a SQLite database and I have checked that it is really connected.
QString databaseName = QFileDialog::getOpenFileName(this,tr("Open database"),
"",
tr("Databáze (*.db)"));
mydb = QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("databaseName");
if (!mydb.open()) {
ui->statusBar->showMessage("Databáze nebyla připojena!",2000);
databaseCheck = false;
}
else if (mydb.open()) {
ui->statusBar->showMessage("Databáze byla úspěšně připojena.",2000);
databaseCheck = true;
}
This is part of the code from the Mainwindow.cpp which sets up the database connection. The database is declared in mainwindow.h, all is functioning in this part.
Here I got a form which returns some data about an employee that I want to create in the database. databaseCheck is a bool that tells me if the database is connected properly. And those variables name, surname etc. in this case are declared in mainwindow.h as QString.
if (databaseCheck) {
form = new Form(this);
form->setWindowTitle("Formulář informací o zaměstnanci.");
form->exec();
name = form->getName();
surname = form->getSurname();
id = form->getId();
date = form->getDate();
telephone = form->getTelephone();
salary = form->getSalary();
state = form->getState();
QSqlQuery query(mydb);
query.prepare("INSERT INTO employees (jmeno,prijmeni,datumnarozeni,telefon,plat,stav) "
"VALUES (:name, :surname, :date, :telephone, :salary , :state)");
query.bindValue(":name", name);
query.bindValue(":forename", surname);
query.bindValue(":date", date );
query.bindValue(":telephone", telephone);
query.bindValue(":salary", salary);
query.bindValue(":state", state );
query.exec();
}
After I fill up the form with some data about the employee and accept it, it does not send anything to the database. I am checking the database with DB Browser for SQLite and the table employees is totally empty. Can anybody help me?
Your SQL seems correct, the best approach is probably to write something like this.
if (!query.exec())
qDebug() << query.lastError();

QSqlDatabase::record(const QString &tablename) returns empty record

I have already read this question. I want to get field names of a table using method QSqlDatabase::record(const QString &tablename). But it always returns an empty record. I can query database tables by QSQLQuery properly. My database is a SQL Server database.
Actually you should get.
As you are saying SQL server, try with "#yourtablename". I mean to say prepend "#" before your tablename in your QString.
if no luck,
Check your table name. (spaces or additional chars etc..)
Type cast to QString (safe side). Or create a QString object with table name and pass it.
Trim the QString, before passing it.
Still for some reason if you are not getting the field names, try below steps.
Your QSqlRecord QSqlDatabase::record(const QString &tablename) const will return a QSqlRecord object
First get the number fields in record
int QSqlRecord::count() const
Loop the count (ex: using for) and get the field name for each index using below function
QString QSqlRecord::fieldName(int index) const
Some pseudo code below: (assuming you have successful connection established, Not compiled and not tested.)
QSqlRecord rec = QSqlDatabase::record("Your table name");
int count = rec.count();
QStringList fieldNames;
For (int i =0; i<count; i++)
{
fieldNames.push_back(rec.fieldName(i);
}
By Select Query:
QSqlQuery select;
select.prepare("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'YourTableName'");
if (select.exec() && select.next()) {
QSqlRecord record = select.record();
}

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

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().
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).

Showing output of sql query inside a QLabel

I am writing a qt gui application where I am planning to show the output of an sql query inside a QLabel.
Now population the output inside a QTableView model is simple enough and that I can do using;
QSqlDatabase dbSqlite = QSqlDatabase::addDatabase("QSQLITE"); //these 2 lines for SQLite DB connection
dbSqlite.setDatabaseName("/home/aj/test.db");
dbSqlite.setUserName("aj");
QString MyQuerySqlite = ui->sqlite_queryEdit->text(); //take the query from a QLineEdit
dbSqlite.open(); //open db connection
QSqlQuery query(MyQuerySqlite,dbSqlite);
if(query.exec()) //populate in table
{
this->model1=new QSqlQueryModel();
model1->setQuery(MyQuerySqlite);
ui->sqlite_tableView->setModel(model1);
qDebug()<<QDateTime::currentDateTime()<<"SQLITE QUERY SUCCESS "<<dbSqlite.lastError().text();
}
Any idea on how to achieve this inside a QLabel ???
The output of the query will be one single record. For example the name of the world's tallest mountain, or the name of the capital of Engalnd. Just single records.
If you want to use QSqlQueryModel for this, you can use QSqlQueryModel::record ( int row ) to retrieve a specific record and then QSqlRecord::value ( int index ) to get a field's value :
QString str = model1->record(0).value(0).toString();
label->setText(str);
You can get result with value method. For example:
QString country;
QSqlQuery query("SELECT country FROM artist");
while (query.next()) {
country.append( query.value(0).toString() + " ");
}
label->setText(country);
Also you can read data from model1. Something like:
label->setText(model1->data(model1->index(0,0),Qt::DisplayRole).toString());