Sqlite Update query with SqliteModernCpp - sql

I am using the SqliteModernCpp library. I have a data access object pattern, including the following function:
void movie_data_access_object::update_movie(movie to_update)
{
// connect to the database
sqlite::database db(this->connection_string);
// execute the query
std::string query = "UPDATE movies SET title = " + to_update.get_title() + " WHERE rowid = " + std::to_string(to_update.get_id());
db << query;
}
Essentially, I want to update the record in the database whose rowid (the PK) has the value that the object to_update has in its parameter (which is returned by get_id()).
This code yields an SQL logic error. What is the cause of this?

It turned out single quotes (') within the query string being created were missing. The line should be:
std::string query = "UPDATE movies SET title = '" + to_update.get_title() + "' WHERE rowid = " + std::to_string(to_update.get_id());

Since there is no UPDATE example in the official docs on github, This is how UPDATE queries should be implemented with prepared statements and binding
#define MODERN_SQLITE_STD_OPTIONAL_SUPPORT
#include "sqlite_modern_cpp.h"
struct Book {
int id;
string title;
string details;
Book(int id_, string title_, string details_):
id(std::move(id_)),
title(std::move(title_)),
details(std::move(details_)) {}
}
int main() {
Book book = Book(0, "foo", "bar")
sqlite::database db("stackoverflow.db");
// Assuming there is a record in table `book` that we want to `update`
db <<
" UPDATE book SET "
" title = ?, "
" details = ? "
" WHERE id = ?; "
<< book.title
<< book.details
<< book.id;
return 0;
}

Related

SQLite error in QT - QSqlError("", "Parameter count mismatch", "")

I'm trying to simply count the amount of records that has a 'true' status.
this is the SQLite table structure:
CREATE TABLE Suppliers(ID INTEGER PRIMARY KEY AUTOINCREMENT,Name varchar(50),Number varchar(15),URL varchar(70),Status bool,ShippingCost integer)
I am then calling a query from QT as follows:
int SQLiteController::ActiveSupplierCount()
{
int count = 0;
QSqlQuery Query;
Query.prepare("SELECT *"
"FROM Suppliers"
"WHERE Status = (:Status)");
Query.bindValue(":Status", true);
Query.exec();
qDebug() << Query.lastError();
while(Query.next() == true)
{
count++;
}
qDebug() << count;
return count;
};
The last error returned here is "Parameter count mismatch"
and I cannot figure out why... There is only 1 parameter, and I assign to that 1 parameter.
Try to add some extra spaces after each line of your query like this
Query.prepare("SELECT * "
"FROM Suppliers "
"WHERE Status = (:Status)");

Spring data repository query to retrieve values containing null

I have following User table and repository.
User:
id;name;job;age
1;steve;nurse;33
2;steve;programmer;null
3;steve;programmer;null
Repository method:
#Query("SELECT u FROM User u WHERE ("
+ "LOWER(u.name) = LOWER(:name) AND "
+ "LOWER(u.beruf) = LOWER(:job) AND "
+ "LOWER(u.alter) = LOWER(:age))")
public List<User> findUsers(#Param("name") String name,
#Param("job") String job,
#Param("age") String age);
If I call the repository method with following parameters
String name = "steve";
String job = "programmer";
List<User> result = repository.findUsers(name, job, null); // empy list ..why ?
I get an empty list as result, although I expect to get the entities with id=2 and id=3 as result.
What am I doing wrong ? How should I change the query to get the two entities as result.
Thanks
According to the documentation this behaviour is normal there is no way to ignore null fields. using #Query method.
instead you can use the query method specifications.
more information [here][jpa documentaiton]
if you want to keep your existing method you can also go like this:
#Query("SELECT u FROM User u WHERE ("
+ "LOWER(u.name) = LOWER(:name) AND "
+ "LOWER(u.beruf) = LOWER(:job) AND "
+ "( " +
" :age is null or LOWER(u.alter) = LOWER(:age) " +
")"
)
public List<User> findUsers(#Param("name") String name,
#Param("job") String job,
#Param("age") String age);

PetaPoco db.SingleOrDefault<T> passing in where name as well as value

I am trying to write a generic method to call DB records.
All works except to make the method useful I need to passing the WHERE name value too...as well as the value to match.
Something like this...
T values = db.SingleOrDefault<T>("WHERE " + name + " = #0", value);
This works but its a bit of a clunk!
string sql = "WHERE " + name + " = #0";
T values = db.SingleOrDefault<T>(sql, value);
Can this be done with different syntax?
Thanks
You can create an extension method to hide the syntax if that bothers you
public static T SingleOrDefaultWithWhere<T>(this PetaPoco.Database db, string name, object value) {
string sql = "WHERE " + name + " = #0";
return db.SingleOrDefault<T>(sql, value);
}
And then just call
T values = db.SingleOrDefaultWithWhere<T>(name, value);

MERGE INTO multiple statements at once Oracle SQL

I have a merge into statement as this :
private static final String UPSERT_STATEMENT = "MERGE INTO " + TABLE_NAME + " tbl1 " +
"USING (SELECT ? as KEY,? as DATA,? as LAST_MODIFIED_DATE FROM dual) tbl2 " +
"ON (tbl1.KEY= tbl2.KEY) " +
"WHEN MATCHED THEN UPDATE SET DATA = tbl2.DATA, LAST_MODIFIED_DATE = tbl2.LAST_MODIFIED_DATE " +
"WHEN NOT MATCHED THEN " +
"INSERT (DETAILS,KEY, DATA, CREATION_DATE, LAST_MODIFIED_DATE) " +
"VALUES (SEQ.NEXTVAL,tbl2.KEY, tbl2.DATA, tbl2.LAST_MODIFIED_DATE,tbl2.LAST_MODIFIED_DATE)";
This is the execution method:
public void mergeInto(final JavaRDD<Tuple2<Long, String>> rows) {
if (rows != null && !rows.isEmpty()) {
rows.foreachPartition((Iterator<Tuple2<Long, String>> iterator) -> {
JdbcTemplate jdbcTemplate = jdbcTemplateFactory.getJdbcTemplate();
LobCreator lobCreator = new DefaultLobHandler().getLobCreator();
while (iterator.hasNext()) {
Tuple2<Long, String> row = iterator.next();
String details = row._2();
Long key = row._1();
java.sql.Date lastModifiedDate = Date.valueOf(LocalDate.now());
Boolean isSuccess = jdbcTemplate.execute(UPSERT_STATEMENT, (PreparedStatementCallback<Boolean>) ps -> {
ps.setLong(1, key);
lobCreator.setBlobAsBytes(ps, 2, details.getBytes());
ps.setObject(3, lastModifiedDate);
return ps.execute();
});
System.out.println(row + "_" + isSuccess);
}
});
}
}
I need to upsert multiple of this statement inside of PLSQL, bulks of 10K if possible.
what is the efficient way to save time : execute 10K statements at once, or how to execute 10K statements in the same transaction?
how should I change the method for support it?
Thanks,
Me
the most efficient way would be one that bulk-loads your data into the database. In comparison to one-by-one uploads (as in your example), I'd expect performance gains of at least 1 or 2 orders of magnitude ("bigger" data means less to be gained by bulk-inserting).
you could use a technique as described in this answer to bulk-insert your records into a temporary table first and then perform a single merge statement using the temporary table.

ActionScript and SQLite parameters on Select using Like

I tried looking on google but without luck...
I have a SELECT SQLStatement and I want to use the LIKE operator but the parameters won't work and the query give me an error
public function getUsersList(username:String):SQLStatement
{
selectRecord= new SQLStatement();
selectRecord.sqlConnection = connection;
selectRecord.text =
"SELECT id_user, username,password,profile,leg_cliente " +
"FROM userlist " +
"WHERE username like '%:username%'";
selectRecord.parameters[":username"] = username;
return selectRecord;
}
The error I got is
':username' parameter name(s) found in parameters property but not in
the SQL specified.
I solved putting the wildcard % in the parameters instead of the statement...
selectRecord.text =
"SELECT id_user, username,password,profile,leg_cliente " +
"FROM userlist " +
"WHERE username like :username";
selectRecord.parameters[":username"] = "%"+ username+"%";
The starting problem was triggered because the query was like
selectRecord.text =
"SELECT id_user, username,password,profile,leg_cliente " +
"FROM userlist " +
"WHERE username like '%:username%'";
Putting the single quote in the statement won't let the statement to set the parameter, I suppose because the parameter key (in statement.text) is seen as a text and not a parameter itself...
This is a weird issue I've been stuck with for quite some time now. One solution I've used is like this:
var statementText:String="SELECT id_user, username,password,profile,leg_cliente " +
"FROM userlist " +
"WHERE username like '%:username%'";
var params:Dictionary=new Dictionary();
params[":username"] = username;
for(var key:Object in params) {
while(statementText.indexOf(key.toString()) >= 0) {
statementText= statementText.replace(key, params[key]);
}
}
selectRecord.text = statementText;