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

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

Related

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.

List data from two table in tableView

How can I list data from two table in tableView?
Database (Example) Sqlite:
tb_sales
tb_product
tb_value
tb_customer_id (Customer Id "tb_customer")
tb_customer
tb_customer_id (id primary key)
tb_name
tb_state
With QSqlRelationalTableModel fetch only the client's name. Also need the state.
model= new QSqlRelationalTableModel(this);
model->setTable("tb_sales");
model->setRelation(2, QSqlRelation("tb_customer", "tb_customer_id", "tb_name"));
model->select();
ui->tableView->setModel(model);
QSqlRelationalTableModel only allows you to include one column from the secondary table. You can use QSqlQueryModel to have a query in which you join the two tables :
QSqlQueryModel *model = new QSqlQueryModel;
model->setQuery("SELECT tb_sales.* , tb_customer.tb_name, tb_customer.tb_state FROM tb_sales LEFT JOIN tb_customer ON tb_sales.tb_customer_id = tb_customer.tb_customer_id");
ui->tableView->setModel(model);

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.

Updating a record in QSqlTableModel

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.