Updating a record in QSqlTableModel - c++

I am trying to update a record and i have this:
tableModel->select();
QModelIndex index = ui.tableView->currentIndex();
QString sqlQuery = QString("UPDATE %1 SET firstname=:firstname, lastname=:lastname, country=:country, city=:city WHERE id=:id)").arg(tableName);
query.prepare(sqlQuery);
QSqlRecord recordz = tableModel->record(index.row());
query.bindValue(":firstname", ui.fEdit->text());
query.bindValue(":lastname", ui.lnEdit->text());
query.bindValue(":country", ui.cEdit->text());
query.bindValue(":city", ui.cityEdit->text());
query.bindValue(":id", recordz.value("id").toInt());
query.exec();
tableModel->submitAll();
The application compiles without errors but it won't save any edits.

query.bindValue(":id", ui.tableView->currentIndex());
There's your offending line of code. You can use the data functions to try return the actual index or value, but remember your tableView index != your SQL database index. You ever drop a row your index on database will be different to your index in Qt, so you'll need to include the actual DB ID into your initial SQL queries and keep it stored alongside the other values, and then return it when you run your update query.

Related

How to insert programmatically a value in a new row of a QtableView

I'm using a QtableView to display and edit data from a QsqlTableModel.
Everything's fine : data from a postgreSQL table is displayed, and user can edit it and save modifications.
I want to add a row when uses click on a button. I use the insertRecord method from my QslTableModel.
The row is correctly added in the QTableView.
My problem is :
I want to insert a value from a query in the first cell of this new row. (to automatically populate an unique identifier).
This is my code :
def ajoutlgn(self):
query_idNewLine = QtSql.QSqlQuery(self.db)
if query_idNewLine.exec_('SELECT sp_idsuivi+1 FROM bdsuivis.t_suivprev_tablo ORDER BY sp_idsuivi DESC LIMIT 1'):
while query_idNewLine.next():
identifiant = query_idNewLine.value(0)
#print identifiant
record = QtSql.QSqlRecord()
record.setValue(1,identifiant)
self.model.insertRecord(self.model.rowCount(), record)
The value is not inserted in the new row (but if I enter a value by hand, it works perfectly).
Nevertheless, the query is OK (as I can see with the « print identifiant » line, which returns the expected integer).
Do you see what I'm doing wrong ?
Are there other methods to insert programmatically a value in a QTableView cell?
Or do I have to use a QitemDelegate ?
Thanks for advance.
Finally I found the solution :
This line creates a record, but not a record for my QsqlTableModel
record = QtSql.QSqlRecord()
I replaced it with this one, and it works perfectly :
record = self.model.record()

How to get one record from sqlite and display in tableview

What I want to do is take the input from a text field (i.e cust_name), match and fetch the record from database with column cust_name.
Database has table cust and column cust_name, address. I want to find a way to display the data in tablview of QSqlTableModel.
QSqlTableModel *model = new QSqlTableModel;
model->setTable("cust");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
ui->tableView->setModel(model);
ui->tableView->setColumnHidden(0,1);
ui->tableView->setColumnHidden(5,1);
ui->list->setModel(model);
ui->list->setModelColumn(1);
model->select();
This successfully displays the whole table named cust. I want to be able to change it into displaying the single record matching the search term.
Use function index() to access custom row/column.
QSqlTableModel *model = new QSqlTableModel;
int value = model->index(row,column).data().toInt();
In your situation like this:
int value = model->index((model->rowCount()-1),column).data().toInt();
or custom sql query :
SELECT * FROM tablename ORDER BY id DESC LIMIT 1;

Creating a new table in database with description from existing table as an input

I have written a QT GUI application that connects to an Oracle Database and performs query and shows the output in a QTableView.
QString host_name=ui->lineHostName->text();
QString db_name=ui->lineDatabaseName->text();
QString user_name=ui->lineUserName->text();
QString pass_word=ui->linePassword->text();
QString port_no=ui->linePortNumber->text();
QSqlDatabase db = QSqlDatabase::addDatabase("QOCI");
db.setHostName(host_name);
db.setDatabaseName(db_name);
db.setUserName(user_name);
db.setPassword(pass_word);
db.setPort(port_no.toInt());
QString MyQuery = ui->lineQuery->text();
db.open();
QSqlQuery query(MyQuery,db);
if(query.exec())
{
this->model=new QSqlQueryModel();
model->setQuery(MyQuery);
ui->tableViewOra->setModel(model);
}
After running the program, I tried to use this (as a substitute of the DESC )---
SELECT
column_name "Name",
nullable "Null?",
concat(concat(concat(data_type,'('),data_length),')') "Type"
FROM user_tab_columns
WHERE table_name='my_table_number_one';
And the column names, null parameter and data type was shown on the QTableView
Now my question is, can I use this information in the QTableView to create another table with same Column names and data type ??? (Basically creating a copy of my queried table table).
EDIT
After suggestions i tried modifying with---
QString query_to_replicate;
query_to_replicate=QString("CREATE OR REPLACE TABLE %1 AS %2").arg("AJ_REPLACEMENT_TESTING").arg(ui->lineEdit->text());
QSqlQuery query_second(query_to_replicate,db);
if(query_second.exec())
{
ui->r_pop_Button->setStyleSheet("QPushButton {background-color: rgb(0, 255, 0);}");
this->model_relocate=new QSqlQueryModel();
model_relocate->setQuery(query_second);
ui->tableView2->setModel(model_relocate);
while (model_relocate->canFetchMore())
model_relocate->fetchMore();
qDebug()<<QDateTime::currentDateTime()<<"Query SUCCESS ";
db.close();
}
now it worked twice, without throwing errors and created replicated copies in the oracle database (I used different names for replicated table before building).
But after running successfully twice, it seized replicating. Situation is completely clueless. I am not getting any errors during build / compile time.
You can do this by using CREATE TABLE AS SELECT:
QString sql = "CREATE TABLE %1 AS %2"
.arg(yourNewTableName)
.arg(ui->lineQuery->text());
// and execute this sql code on your QSqlDatabase as you do it above
It will create new table, with name from "yourNewTableName" variable and copy data from select query to new table.
Code update:
QString query_to_replicate;
query_to_replicate=QString("CREATE OR REPLACE TABLE %1 AS %2").arg("AJ_REPLACEMENT_TESTING").arg(ui->lineEdit->text());
QSqlQuery query_second(query_to_replicate,db); // query will be executed there! weird, but...
if (query_second.lastError().isValid())
{
qDebug() << query_second.lastError().text(); // error happens
}
else
{
qDebug() << "Table created successfully";
}
Also, you must #include <QSqlError> in the top of file, to use QtSql errors.

connect QTreeWidgetItem to database

Im working on a project where im trying to build a QTreeWidget that has multiple QTreeWidgetItems
and once i click on a particular item it connects to a database and shows a query result in a tableview model, until now every thing works fine.
the problem is that i want each item to output different resut depending on some criteria on the same table where this criteria is only changing the value of an attribute, and this value is the same of the item name. for example item named 122 and the table has atribute called no. when we click on item 122 the result of this query must be shown (select * from table where no=122)
any help :)
I am assuming you have a QTableView backed by a QSqlQueryModel or QSqlTableModel.
You can connect to the signal QTreeWidget::itemSelectionChanged() and then in the slot you get the current item with selectedItems()[0]. Then you create your query:
QSqlQuery query;
query.prepare("select * from table where no=:no");
query.bindValue(":no", number);
query.exec();
Finally you can use setQuery (const QSqlQuery & query) on the model. This should update your view.
I hope I understood correctly what you want to achieve.

Why do INSERT and DELETE screw up QTableView (Qt, C++, sqlite)?

After setting an INSERT or DELETE query on QSqlQueryModel, my QTableView becomes screwed up. For example I hid the ID column by calling view->hideColumn(ID); but after an INSERT or DELETE the ID column becomes visible.
How can I automatically reset my view to the previous settings in these cases?
I guess the problem is in QSqlQueryModel::setQuery you're eventually calling every time content gets reloaded and rows inserts\deletes. Looking at the setQuery implementation I would suggest: depending on the query your model can be reset including columns settings change which should trigger view columns update.
As Qt documentation suggests:
The QSqlQueryModel class provides a
read-only data model for SQL result
sets.
so I would use direct QSqlQuery calls for the data updates and then would reload the model with the same query. Or consider switching to QSQLTableModel, which is quite handy for single table content manipulation and supports inserts updates and deletes. See if an example below would work for you:
set up database, view and model:
QSqlTableModel *_model;
QTableView *_view;
...
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(":memory:");
db.open() ;
QSqlQuery query;
query.prepare("CREATE TABLE IF NOT EXISTS person (id INTEGER UNIQUE PRIMARY KEY, name VARCHAR(30))");
query.exec();
query.prepare("INSERT INTO person (name) VALUES ('test1')");
query.exec();
query.prepare("INSERT INTO person (name) VALUES ('test2')");
query.exec();
_model = new QSqlTableModel(this, db);
_model->setTable("person");
_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
_model->select();
_model->setHeaderData(1, Qt::Horizontal, tr("name"));
_model->setSort(1, Qt::AscendingOrder);
_view = new QTableView(this);
_view->setModel(_model);
_view->hideColumn(0);
add new row:
QSqlRecord record;
_model->insertRecord(-1, record);
delete selected row(s):
QModelIndexList selected = _view->selectionModel()->selectedIndexes();
for (int i = 0; i < selected.size(); ++i)
_model->removeRows(selected.at(i).row(), 1);
submit changes:
_model->submitAll();
hope this helps, regards