How to use the MySQL count() function in QT? - c++

I want to get the total number of rows in a table. How can I achieve this?
I wrote the code as follows:
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
db.setHostName("localhost");
db.setDatabaseName("Dictionary");
db.setUserName("root");
db.setPassword("cinesoft");
bool ok = db.open();
int ID;
//SELECT COUNT(*) FROM icecream
QString IDnosql="SELECT * FROM Dictionary.TABLE_ENGLISH";
if(ok)
{
QSqlQuery IDquery(db);
IDquery.prepare(IDnosql);
int Id=IDquery.numRowsAffected();
IDquery.exec();
// int Id=IDquery.numRowsAffected();
QMessageBox::information(0,"sucess",QString::number(Id));
}
I use the count command. I want to get the total no of rows in my table and store to an integer variable.

You can prepare a QSqlQuery with the COUNT command:
QSqlQuery q;
q.prepare(QString("SELECT COUNT (*) FROM %1").arg(tableName));
q.exec();
int rows= 0;
if (q.next()) {
rows= q.value(0).toInt();
}
Check QSqlQuery for more details

Why don't you just use the query SELECT COUNT(*) from Dictionary.TABLE_ENGLISH - this will give you the number of rows in the table. Then get this value from the result set and store it in an integer variable.

When using a COUNT statement, you can use QSqlQuery::value( int index ) like when selecting a single value:
QString IDnosql="SELECT COUNT( * ) FROM Dictionary.TABLE_ENGLISH";
if(ok)
{
QSqlQuery IDquery(db);
IDquery.prepare(IDnosql);
if( !IDquery.exec() )
{
// TODO: perform error handling here!
}
if( !IDquery.next() )
{
// TODO: Error handling: Query did not return a result (no row, which should not be possible when using a count statement as you would always get 1 row)
}
int Id = IDquery.value( 0 ).toInt();
QMessageBox::information(0,"sucess",QString::number(Id));
}

To get the total number of rows in a table A you simply
SELECT count(*) from A;
Then you need to convert the result to an integer.

Related

QVariant returns invalid meanwhile the value is valid

I have a small function like this
bool QcgDatabase::onceindb(const QString& userId)
{
mDb->prepareSqlQuery("SELECT count(*) FROM mytable WHERE userid=:userId;", "database");
mDb->prepareBindValue(":userId", userId);
mDb->sqlExec();
bool d = mDb->sqlQuery().isActive();
QVariant c = mDb->sqlQuery().value(QString("count(*)"));
int e = c.toInt();
if (e == 1) {
return true;
}
else {
return false;
}
}
When I do this command in SQL, the result looks like this
I just want to take value 2 for comparison below, but in the code when I debug, QVariant c always return invalid, therefore e is always = 0. I thought my SQL command is not active, but when I debug, bool dalways return true. Do you guys know why? how can I receive 2 as expected ?
Your problem is that you're trying to fetch the result from a column with a special (and in some places invalid) name count(*). You can set an alias for the column and fetch the value using that column alias:
...
mDb->prepareSqlQuery("SELECT count(*) as count FROM mytable WHERE userid=:userId;", "database");
...
QVariant c = mDb->sqlQuery().value("count");
...
And checking return values for error states is also good practice...

Selecting multiple tables MySQL

I'm using MySQL connector C 6.0.2, I need to select Table1 and read some values there then switch to table2 and read the values there too etc, I have more than two tables I need to switch from table to table. How can I do this ?
example code:
connect=mysql_real_connect(connect,SERVER,USER,PASSWORD,DATABASE,0,NULL,0);
if(connect)
{
MYSQL_RES *res_set;
MYSQL_ROW row;
////table1
mysql_query(connect,"SELECT * FROM `Table1` WHERE `Column2`='1234'");
unsigned int i = 0;
res_set = mysql_store_result(connect);
unsigned int numrows = mysql_num_rows(res_set);
if(numrows==0)
{
return false;
}else
{
while ((row = mysql_fetch_row(res_set)) != NULL)
{
if(strcmp(row[2], "true")==NULL)
{/////////Here I need to read or get the values from Table2
///Select table two
}else
return false;
}
}
}
Update: I think I have solved it, it was pretty simple
connect=mysql_real_connect(connect,SERVER,USER,PASSWORD,DATABASE,0,NULL,0);
if(connect)
{
MYSQL_RES *res_set;
MYSQL_ROW row;
////table1
mysql_query(connect,"SELECT * FROM `Table1` WHERE `Column2`='1234'");
res_set = mysql_store_result(connect);
unsigned int numrows = mysql_num_rows(res_set);
if(numrows==0)
{
return false;
}else
{
while ((row = mysql_fetch_row(res_set)) != NULL)
{
if(strcmp(row[2], "true")==NULL)
{/////////Here I need to read or get the values from Table2
///Select table two
MYSQL_RES *res_set2;
////table2
mysql_query(connect,"SELECT * FROM `Table2` WHERE `Column2`='1234'");
res_set2 = mysql_store_result(connect);
unsigned int numrows2 = mysql_num_rows(res_set2);
if(numrows2==0)
{
//no result
}else
{
//do something
}
}else
return false;
}
}
}
You have the res_set variable that you got from your query; you'd get another variable from your second query. You don't switch between tables, you just get the right values from the right query results.
Also note that this sounds a lot like you should be doing this inside your SQL query, and not inside your code, but that entirely depends on what you want to do.
I suggest you play with your SQL statement to return the result sets from both tables.
Research the "SELECT JOIN" statement.
The rule of thumb is to have the data perform most of the database work, including searching multiple tables.

Columns number. QMYSQLResult::data: column out of range

Have database. Have query with unknown count of columns. Need to put all answer in QList
database = QSqlDatabase::addDatabase("QMYSQL");
...
QString sql = "Select * from test";
QSqlQuery query = QSqlQuery(database);
query.exec(sql);
QList<QStringList> retList;
Use .isValid() on value.
while (query.next()) {
int count = 0;
bool flagValues = true;
QStringList row;
while(flagValues)
{
QVariant value = query.value(count);
if(value.isValid() && !(count == memCount) )
{
count++;
row.append(value.toString());
}
else
{
flagValues = false;
}
}
retList.append(row);
All is ok, but i have a messages (not error) like in every row. :
QMYSQLResult::data: column 3 out of range
I do not want to use additional query (like information_schema) to know columns number.
Use query.record().count() to obtain the number of columns. Thus:
database = QSqlDatabase::addDatabase("QMYSQL");
...
QString sql = "Select * from test";
QSqlQuery query = QSqlQuery(database);
query.exec(sql);
const int memCount = query.record().count();
// query loop goes here

How to count the numbers of columns while iterating over results using Oracle OCCI library?

Help me, I want to make a generic function that get the results of any query string and puts all rows into another variable. When iterating over a row, how can I know the numbers of columns available?
Environment *env = Environment::createEnvironment();
Connection *conn = env->createConnection("user","pass");
quantLinhas = 0;
if( conn != NULL ) {
Statement *stmt = conn->createStatement(query);
ResultSet *rs = stmt->executeQuery();
resultadoSQL->linhas.clear();
while (rs->next()) {
aux.campos.clear();
numbers_colums = rs->whatever_method() //WHAT DO I DO HERE??
for(i = 0; i < numbers_colums ; i++) {
aux.campos.push_back( rs->getString(i) );
quantLinhas++;
}
resultadoSQL->linhas.push_back( aux );
}
stmt->closeResultSet(rs);
conn->terminateStatement(stmt);
env->terminateConnection(conn);
}
According the documentation you can use getColumnListMetaData function. The number of elements in the returned vector might be what you want. You may check if each element is of PTYPE_COL to ensure it.
try this
vector<MetaData> columnList = rs->getColumnListMetaData();
numbers_colums = columnList.size();
columnList.clear();
it worked for me.
source link

why is my transaction not rolling back? Qt Mysql odbc driver

I'm using Qt 4.8.3 and MySQL ODBC 3.51 Driver. When my transaction fails because of a duplicate unique Id in the second table the insert in the first table is not rolled back. Can anyone spot the error?
struct Property //see OMG's Property Service
{
std::string name;
boost::any value;
Property();
Property(const std::string &inName, const boost::any &inValue):name(inName),value(inValue){}
};
Property myFunction(QSqlDatabase &db, int amount)
{
assert(db.driver()->hasFeature(QSqlDriver::Transactions) == true);
db.transaction();
QSqlQuery query(db);
Property ret("MyPropertyTag",0);
try{
query.exec("LOCK TABLES table1 WRITE, table2 WRITE");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
for(int i=0;i<amount;i++)
{
query.exec("INSERT INTO table1 (someUniqueValue, newestId, Created) VALUES ('"+QString::number(i)+"', '1', NOW())");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
query.exec("SELECT id FROM table1 WHERE someUniqueValue = '"+QString::number(i)+"'");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
if(query.next() == false) { throw std::exception("no result for insert id"); }
auto Id1 = query.value(0).toString();
query.exec("INSERT INTO table2 (table1_id, Changed, Created) VALUES ('"+Id1+"', NOW(), NOW())");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
query.exec("SELECT Id, table1_id FROM table2 ORDER BY Id DESC LIMIT 1");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); } //lets say this throws
if(query.next() == false || query.value(1).toString() != Id1) { throw std::exception("no result for inserted id"); }
auto Id2 = query.value(0).toString();
query.exec("UPDATE table1 SET newestId = '"+Id2+"' WHERE Id = '"+Id1+"'");
if(query.lastError().isValid()) { throw std::exception(query.lastError().text().toAscii()); }
}
db.commit();
ret.value = amount;
} catch(std::exception &e) {
query.finish();
db.rollback();
ret.value = std::string("error:") + e.what();
}
query.exec("UNLOCK TABLES");
query.finish();
return ret;
}
Your Tables problably are Myisam, changed them to Innodb to allow transactions.
To change the AutoCommit (I'm not sure if it's necessary) you can try it this way:
mysql> SET autocommit=0;
Query OK, 0 rows affected (0.00 sec)
but this will be working only with the current connection, if you need to apply to all the DB you need to change the DB variables.