I am performing queries against a MySQL database, and use code similar to below throughout my app. But for some reason the update below says 0 rows affected, when it should be 1. On digging deeper I discovered my bindValue commands don't seem to have any effect.
QSqlQuery* query = new QSqlQuery(m_db)
query->prepare(QString("UPDATE companies SET "
"NAME=:name, "
"ISUSER=:isuser, "
"ISVAR=:isvar, "
"ISOEM=:isoem, "
"CONTACT=:contact, "
"EMAIL=:email, "
"COMMENTS=:comments "
"WHERE ID=:id "
"LIMIT 1"));
query->bindValue(":name",rowData.name);
query->bindValue(":isuser",rowData.isEndUser);
query->bindValue(":isvar",rowData.isVAR);
query->bindValue(":isoem",rowData.isOEM);
query->bindValue(":contact",rowData.contact);
query->bindValue(":email",rowData.email);
query->bindValue(":comments",rowData.comments);
query->bindValue(":id",id);
bool queryOk = query->exec();
if (queryOk) {
qDebug() << query->executedQuery();
qDebug() << query->lastQuery();
qDebug() << query->lastError().text();
qDebug() << rowsAffected;
There must be something different/wrong in the code above causing the output below:
"UPDATE companies SET NAME=:name, ISUSER=:isuser, ISVAR=:isvar, ISOEM=:iSOEM, CONTACT=:contact, EMAIL=:email, COMMENTS=:comments WHERE ID=:id LIMIT 1"
"UPDATE companies SET NAME=:name, ISUSER=:isuser, ISVAR=:isvar, ISOEM=:iSOEM, CONTACT=:contact, EMAIL=:email, COMMENTS=:comments WHERE ID=:id LIMIT 1"
""
0
But I can't see the problem, and the query returns no errors. Yet the query string seems to contain the variable names not substituted.
QSqlQuery::executedQuery() won't show you the bound values, because the idea of bound values is that they never become part of the query itself (which completely eliminates the problem of escaping them). What you see is the actual query submitted to the database. The bound values are submitted to the database alongside the query string (very much same like with QSqlQuery).
As for the rowsAffected being zero, I don't see it being initialized or updated by the code in your example, which is likely why it says 0. you probably want to use query->numRowsAffected() instead.
Finally (not related to any of your questions), you don't need to allocate the QSqlQuery on heap (unless you really need the query to outlive the scope in which it is created) and you can simply allocate it on stack. Fewer dynamic allocations == fewer chances of memory leaks :-)
Related
I'm working to programmatically clean up a field in my dataset by using a Helper column that I will later filter on and remove the 'junk' records. The junk records are ID's, and the valid records are full names (in the format of "Tom Jones"). Almost all (there is a valid name value of "University") junk records do not contain a space. The pseudo code would read
Set Helper_IsName? = True
WHERE ValueField CONTAINS " " unless ValueField = "University"
ELSE False
Here is the M code excerpt that is getting me 95% of the way there:
Helper_IsName? = Text.Contains([OldValue]," ")
All results are good, except when the formula reads "University", it sets the value as FALSE, when I need it to equal TRUE.
I think you can just add that condition with an or:
Helper_IsName? = Text.Contains([OldValue]," ") or [OldValue] = "University"
I got this error recently, and couldn't get rid of it. It's puzzling me, because the exact same request (copy-paste) works from the CLI like a charm.
I am using the C bindings, from a Qt application (I only discovered later that there was a Qt wrapper class for SQL databases).
The request in question is the following :
NSERT INTO classes(score,classe) VALUES((SELECT avg((julianday(arrivee)-julianday(debutCourse))/moyenne) FROM coureurs NATURAL JOIN resultats NATURAL JOIN courses NATURAL JOIN categories WHERE classe='4èmeB' AND moyenne IS NOT NULL),'4èmeB');
The error is :
near "'4èmeB'": syntax error
I have three tables I use there, which are classes, coureurs (runners), resultats (results), courses (races), categories.
For each class, I want to compute the following :
average of (runner's time/average time of its category).
Departure times are stored inside the courses (races) table, arrival times are stored inside the resultats (results) table and categories' average time are stored into categories.moyenne. If you have a more elegant way of performing such a request, I would be pleased to hear it. I would however like to have an explanation of what's going on here. Is this because of the UTF-8 characters ? It didn't seem to be a problem in other places.
In case it helps, here is the relevant C++ code :
void database::voidQuery(QString query)
{
sqlite3_stmt *res;
int rc =sqlite3_prepare_v2(db,query.toStdString().c_str(),query.length(),&res,NULL);
if(rc != SQLITE_OK){
fprintf(stderr, "Error in voidquery : %s in the request %s\n", sqlite3_errmsg(db),query.toStdString().c_str());
return;
}
sqlite3_step(res);
sqlite3_finalize(res);
}
Together with The calling code :
for (QStringList::iterator it = classes.begin();it != classes.end(); ++it)
{
QString query("INSERT INTO classes(score,classe) "
"VALUES(("
"SELECT avg((julianday(arrivee)-julianday(debutCourse))/moyenne) "
"FROM coureurs NATURAL JOIN resultats NATURAL JOIN courses NATURAL JOIN categories "
"WHERE classe='%1' and moyenne is not null),'%2');");
voidQuery(query.arg(*it).arg(*it));
}
classes is a QStringList containing the different rows of a precedent query.
Thanks in advance ! (I hope it's not a trivial problem; it took me quite some time to debug it).
Use
INSERT INTO classes (score,classe)
SELECT avg((julianday(arrivee)-julianday(debutCourse))/moyenne), '4èmeB'
FROM coureurs
NATURAL JOIN resultats
NATURAL JOIN courses
NATURAL JOIN categories
WHERE classe='4èmeB'
AND moyenne IS NOT NULL
I want to do a prepared statement like this:
pstmt=conn->prepareStatement("UPDATE partidos SET i?=? WHERE ID=?");
pstmt->setInt(1,lazo);
pstmt->setString(2,texto[lazo]);
pstmt->setInt(3,var);
pstmt->execute();
"lazo" is a variable in a for loop, texto[lazo] is a variable and var is another int variable.
When I run this query, it throws an exception: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'i?=? WHERE ID=?' at line 1".
It seems that it doesn't replace the '?'.
I tried with stringstreams, but the problem didn't fix.
Thanks.
Finally I opted for this.
stringstream stmtvar;
stmtvar << "UPDATE PARTIDOS SET minuto" << lazo << "='" << texto[lazo] << "' WHERE ID=" << var;
stmt->executeUpdate(stmtvar.str());
It worked perfectly
I have a dynamically generated query, all but one params are optional with one required field.
I thought I would be smart but something very odd happens.
-cfscript
// Standard new query(), set name, datasource etc
query.addParam(value=requiredParam, type=cf_sql_varchar);
sqlStatement = "select ....";
if (optional field 2){
sqlStatement &= "and field like '%?%' ";
query.addParam(value=optionalValue, type=cf_sql_varchar);
}
... optional fields 2,3,4,5 repeats ...
query.execute(sql=sqlStatement);
So when I execute passing only the required field, the query is correct as are the results.
dump shows just the required entry in the sqlParameter (with 2 results)
When I add calls with the optional arguments, only the first (required argument is shown). The optional arguments are NOT shown (in the result dump) and the result set goes to 0 rows. (?? very odd)
I traced it with the debugger, (from cf8 extenstions, cfeclipse, not builder, on CF9 standalone)
The optional field logic was correct, the code was tested and executed.
In the variables pane the params seemed to be added properly but don't show up in the result query, (dump on the result page) only the required one.
I am guessing something odd is happening, but this does not make sense.
Is it possible that all the addParams have to be added together?
Is the like (syntax) the problem?
Why would working with ifs/conditional prevent additional addParams to not work/showup?
Some odd display issue from dump?
Sorry about not providing real code, in a sensitive area.
If you have multiple fields I think it would be best to use the name parameter:
if (optional field 1) {
sqlStatement &= "AND Field LIKE :field1 ";
query.addParam( name="field2", value="%#optionalvalue#%", type=cf_sql_varchar);
}
if (optional field 2) {
sqlStatement &= "AND Field LIKE :field2 ";
query.addParam( name="field2", value="%#optionalvalue#%", type=cf_sql_varchar);
}
Good reading: http://www.bennadel.com/blog/1678-Learning-ColdFusion-9-Using-CFQuery-And-Other-Service-Tags-In-CFScript.htm
Note the bug about putting a space behind the :name in the statement in some cases.
PEBKAC ...
Wrote
if (optional field 2){
sqlStatement &= "and field like '%?%' ";
query.addParam(value=optionalValue, type=cf_sql_varchar);
}
Should have been:
if (optional field 2){
sqlStatement &= "and field like ? ";
query.addParam(value='%#optionalValue#%', type=cf_sql_varchar);
}
Query works properly now, returns correct rows and the parameters used show up in the dump ...
I have a test table using a Microsoft SQL Server that is defined like this:
CREATE TABLE [dbo].[Table] (
[FirstName] NVARCHAR (255) NULL,
[LastName] NVARCHAR (255) NULL
);
There's just one row in the table with the values "person" and "man", respectively.
I'm trying to add a function that will update the values of that row but I keep running into this "[Microsoft][ODBC SQL Server Driver]String data, right truncation State code: 22001" error and I cannot figure out what the problem is. I've looked around and people say that it is caused by the data being too long to fit in the column but that's impossible because the string I'm trying to update with is only two characters, and as you can see in the table definition there is plenty of space for it.
I'm using a prepared statement for optimization purposes and the code creating it looks something like this:
const tString query("UPDATE \"" + tableName + "\" SET " + setClause + " WHERE " + whereClause + ";");
SQLHSTMT statement;
SQLAllocHandle(SQL_HANDLE_STMT, fSQLConnection, &statement);
SQLPrepareW(statement, (SQLWCHAR *) query.mWideStr(), SQL_NTS);`
The query string looks like this:
UPDATE "Table" SET "FirstName" = ?, "LastName" = ? WHERE "FirstName" = ? AND "LastName" = ?;
And then I am binding the parameters like this:
// We have our own string class that we use, which is where the mWideStr() and mGetStrSize()
// come from. mWideStr() returns a pointer to a UCS-2 buffer and mGetStrSize() returns the
// size in bytes.
SQLLEN pcbValue(SQL_NTS);
SQLUSMALLINT paramIndex(1);
// Call this for each parameter in the correct order they need to be bound, incrementing the
// index each time.
SQLBindParameter(statement, paramIndex++, SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_VARCHAR, 255, 0, (SQLPOINTER) paramValue.mWideStr(), paramValue.mGetStrSize(), &pcbValue);
The first and second bound parameters are the new values which are both just "55", then third would be "person" and fourth would be "man".
Then to execute the statements it's just a call to SQLExecute():
SQLExecute(statement);
The call to SQLExecute() fails and then the error is generated and there is some more code that outputs the error message. As far as I can tell this should all be working perfectly fine. I have another database using Oracle that uses the exact same setup and code and it works without any issues, it's just SQL Server that's barfing for some reason. Is there something obviously wrong here that I'm missing? Does SQL Server have some weird rules that I need to add somewhere?
The SQLLEN pcbValue(SQL_NTS); variable being passed to SQLBindParameter() was going out of scope between binding the parameters and executing the statement, which means that some garbage data was being pointed to in the parameter binding. I also realized that you don't need to specify the last parameter. You can just pass NULL and it will act as if it is a nul-terminated string.
So the fix was to remove the SQLLEN pcbValue(SQL_NTS); variable and to just pass NULL to SQLBindParameter() for the last parameter instead.
Stupid mistake, but worth noting I suppose.