QSqlQuery 'Parameter Count Mismatch' - c++

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.

Related

Qt error: QSqlQuery::value: not positioned on a valid record when trying to retrive a stat from a table (QComboBox)

this is the code I'm using to get the GoalsFor stat from this table after the user chooses a team from a ComboBox like this using this code:
void MainWindow::on_hometeam_currentIndexChanged(const QString &hometeam)
{
QString hteam(hometeam);
QSqlQuery q("SELECT GoalsForH FROM teams WHERE TEAM=hteam");
q.exec();
int fieldNo = q.record().indexOf("hometeam");
q.next();
qDebug() << q.value(fieldNo).toInt();
}
But this is what the debugger always shows whenever I choose a team:
QSqlQuery::value: not positioned on a valid record
0
I tried everything I came across on the net and it seems like I'm doing exactly what other users or even the documentation say yet to no avail, any help would be appreciated, thanks !
The problem seems to be with the SQL itself; since hteam isn't actually defined in SQL. I would instead recommend using the prepare function, which can also deal with filtering strings to prevent SQL injections. Something like the below should give you the result you are looking for.
void MainWindow::on_hometeam_currentIndexChanged(const QString &hometeam)
{
QString hteam(hometeam);
QSqlQuery q;
q.prepare("SELECT GoalsForH FROM teams WHERE TEAM=:hteam");
q.bindValue(":hteam", hteam);
if ( !q.exec() ) {
qDebug() << q.lastError();
} else {
int fieldNo = q.record().indexOf("GoalsForH");
while ( q.next() ) {
qDebug() << q.value(fieldNo).toInt();
}
}
}
You were also grabbing indexOf("hometeam"), which isn't actually returned by the query. This then returns -1 which wouldn't be valid. Change this to "GoalsForH" to get the proper column index.

How To Check Database Field is NULL

I have this code snippet that making a call to a database table, where I was to perform some actions, like allocate a room, is the field HostelName is NULL.
But after trying many methods turns out the NULL fields are not being truly observed in my code and the execution always enters the first IF statement even though the field is NULL. Is there really a way to check if a field is NULL and perform some actions accordingly? Am a bit of a novice in Qt and Database.
Note:
MatricNo is the primary key. Which obviously the SELECT statement can return just one record(I guess).
qry.prepare("SELECT * from student where matricno='"+matric+"' and HostelName IS NULL");
qry.exec();
QSqlRecord rec = qry.record();
if(rec.isNull("HostelName"))
{
qry.prepare("UPDATE student set HostelName='"+hostelName+"',RoomNo='"+roomNo+"' where MatricNo='"+matric+"'");
if(qry.exec())
{
qry.prepare("UPDATE Rooms set OccupantsNo=OccupantsNo-1 where HostelName='"+hostelName+"' and roomID='"+roomNo+"'");
if(qry.exec())
{
QMessageBox::critical(this,tr("Error"),tr("Student Room Allocated"));
}
else
{
QMessageBox::critical(this,tr("Error"),qry.lastError().text());
}
}
else
{
QMessageBox::critical(this,tr("Error"),qry.lastError().text());
}
}
else
{
QMessageBox::critical(this,tr("Error"),"Cant Allocate Room: \nStudent Room Already Alloted\nTo Re-Allocate, Go to Edit Student Details");//qry.lastError().text());
}
Consider the following problems in your code:
First: your rec is just null! you are assigning QSqlRecord rec immediately after qry.exec() .. where result is currently located before the first record , you have to position query to first record first QSqlQuery::next()
.. at least this is needed to get your code work.
qry.exec();
qry.next();
QSqlRecord rec = qry.record();
Second: your sql statement have already selected based on HostelName IS NULL
but you are checking the result for rec.isNull("HostelName") ... this is just useless and needless, you probably want rec.isNull("RoomNo") or something else or nothing! but after your select statement the record value of HostelName is always NULL.

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

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

QSqlQuery.record() is always empty

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();
}