Adding several columns in update query - java

Im trying to update several columns in a row through a dynamic query.
columnnames is an Arraylist containing all the names of the columns for the selected table
Arrays.toString(row) contains the user inputs that the row should be updated to.
Im getting this error message at columnnames when trying to run this: No such column[SNO,SNAME,STATUS,CITY]. I dont know of any way to fix this?
query = "UPDATE " + tablename + " SET '" + columnnames + "' = '" + Arrays.toString(row) + "' WHERE " + FirstColumn + " = '" + rowstandard + "'";

You need to update each column separately. You can't pass them each as arrays.
query = "UPDATE " + tablename + " SET "
foreach(int i=0; i< columnnames.length; i++)
{
query+= "'" + columnnames[i] + "' = '" + row[i] + "',"
}
query = StripLastComma(query) //Not sure how to do this in Java.
query +="' WHERE " + FirstColumn + " = '" + rowstandard + "'"

Thats not going to work as the syntax for set is SET ColumnA = :ValueA, ColumnB = :ValueB WHERE " + FirstColumn + " = '" + rowstandard + "'";

As it was pointed out correct syntax for update query is:
UPDATE [LOW_PRIORITY] [IGNORE] table_reference
SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
see Update syntax.
Having said that, I would do something like this (using guava):
StringBuilder query = new StringBuilder();
query.append("UPDATE " + tablename + " SET ");
// build a map of col name/value
Map<String, String> map = Maps.toMap(columnnames, new Function<String, String>(){
#Override
public String apply(String input){
return row[columnnames.indexOf(input)].toString();
}
});
query.append(Joiner.on(",").withKeyValueSeparator("=").join(map));
query.append(" WHERE " + FirstColumn + " = '" + rowstandard + "'");
query.toString();

Related

no such column: hey (code 1 SQLITE_ERROR[1]): , while compiling: SELECT ID FROM ALLWORKHOURS WHERE NOTEMEMOS = hey

Log Cat:
no such column: hey (code 1 SQLITE_ERROR[1]): , while compiling: SELECT ID FROM ALLWORKHOURS WHERE NOTEMEMOS = hey
code:
102) public String getID(String note){
103) SQLiteDatabase db = this.getWritableDatabase();
104) String query = ("SELECT " + COL_0 + " FROM " + TABLE_NAME + " WHERE " + COL_5 + " = " + note);
105) db.rawQuery(query,null);
106) return query;
107) }
I do have a column name hey in my Database
Database Picture
Your terminology is confused.
hey is a value, NOTEMEMOS is a column.
You need to quote the value hey to let the SQL compiler know that it is a string value, rather than a column you are trying to compare against.
String query = ("SELECT " + COL_0 + " FROM " + TABLE_NAME + " WHERE " + COL_5 + " = '" + note + "'");
Just a note, you would be better off using a parameterised query, as using raw values is insecure (see SQL injection).
String query = ("SELECT " + COL_0 + " FROM " + TABLE_NAME + " WHERE " + COL_5 + " = ?"); // That's right, quotes aren't needed for a parameterized query.
String result = "";
Cursor cursor = db.rawQuery(query,new String[] {note} );
if (cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(COL_0));
}
cursor.close();
return result;
Your query should look like this
SELECT ID FROM ALLWORKHOURS WHERE NOTEMEMOS = 'hey'
Let me know if it helps
The way that you concatenate the parameter note creates this sql statement:
SELECT ID FROM ALLWORKHOURS WHERE NOTEMEMOS = hey
so hey is considered a column identifier and not a string literal because it is not enclosed inside single quotes.
You could do this instead:
String query = "SELECT " + COL_0 + " FROM " + TABLE_NAME + " WHERE " + COL_5 + " = '" + note + "'";
and it would work.
But the recommended way is passing parameters as a string array like this:
String query = "SELECT " + COL_0 + " FROM " + TABLE_NAME + " WHERE " + COL_5 + " = ?";
Cursor cursor = db.rawQuery(query, new String[] {note});
return cursor;
This way you don't worry about single quotes as this is taken care of by rawQuery().
I guess you want to return the Cursor object and not the sql query string, right?

How simplify this code?

This code serves to update a customer's data in sql. How I can simplify this code? Is there another way to do this?
if (!clienteOld.getNome().equalsIgnoreCase(clienteNew.getNome())) {
stmt.executeUpdate("UPDATE CLIENTES SET NOME = '" + clienteNew.getNome() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- NOME=" + clienteNew.getNome());
}
if (!clienteOld.getDataNascimento().equalsIgnoreCase(clienteNew.getDataNascimento())) {
stmt.executeUpdate("UPDATE CLIENTES SET DATA_NASCI = '" + clienteNew.getDataNascimento() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- DATA NASCIMENTO=" + clienteNew.getDataNascimento());
}
if (!clienteOld.getMorada().equalsIgnoreCase(clienteNew.getMorada())) {
stmt.executeUpdate("UPDATE CLIENTES SET MORADA = '" + clienteNew.getMorada() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- MORADA=" + clienteNew.getMorada());
}
if (!clienteOld.getPais().equalsIgnoreCase(clienteNew.getPais())) {
stmt.executeUpdate("UPDATE CLIENTES SET PAIS = '" + clienteNew.getPais() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- PAIS=" + clienteNew.getPais());
}
if (!clienteOld.getNacionalidade().equalsIgnoreCase(clienteNew.getNacionalidade())) {
stmt.executeUpdate("UPDATE CLIENTES SET NACIONALIDADE = '" + clienteNew.getNacionalidade() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- NACIONALIDADE=" + clienteNew.getNacionalidade());
}
if (!clienteOld.getBI().equalsIgnoreCase(clienteNew.getBI())) {
stmt.executeUpdate("UPDATE CLIENTES SET BI = '" + clienteNew.getBI() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- BI=" + clienteNew.getBI());
}
if (!clienteOld.getTipoIndentificaçao().equalsIgnoreCase(clienteNew.getTipoIndentificaçao())) {
stmt.executeUpdate("UPDATE CLIENTES SET TIPO_IDENT = '" + clienteNew.getTipoIndentificaçao() + "' WHERE ID = " + id1 + ";");
criarLog("Ficha do cliente: " + clienteOld.getNome() + " foi atualizada -- TIPO IDENTIFICAÇAO=" + clienteNew.getTipoIndentificaçao());
}
Try this logic:
StringBuilder sql = new StringBuilder("UPDATE CLIENTES SET ");
Map<String, String> cols = new HashMap<>();
if (!clienteOld.getNome().equalsIgnoreCase(clienteNew.getNome())) {
cols.put("NOME", clienteNew.getNome());
}
if (!clienteOld.getDataNascimento().equalsIgnoreCase(clienteNew.getDataNascimento())) {
cols.put("DATA_NASCI", clienteNew.getDataNascimento());
}
// and the other if statements
Then you can iterate the map and build your actual update statement:
int cnt = 0;
for (Map.Entry<Integer, Integer> entry : cols.entrySet()) {
if (cnt > 0) sql.append(", ");
sql.append(entry.getKey()).append(" = '").append(entry.getValue()).append("'");
++cnt;
}
sql.append(" WHERE ID = ").append(id1).append(";");
But note that this approach is not SQL injection safe. If these values are coming from the outside, e.g. a UI, then you should absolutely be using a prepared statement. There is nothing inherently wrong with using a separate statement for each if condition. I only answered to show that you can cleanup your current approach, should it be appropriate.
if (!oldClient.getName().equalsIgnoreCase(newClient.getName())) {
stmt.executeUpdate("UPDATE CLIENTS SET NAME = '" + newClient.getName() +
"' WHERE ID = " + id1 + ";");
}
if (!oldClient.getBirthDate().equalsIgnoreCase(newClient.getBirthDate())) {
stmt.executeUpdate("UPDATE CLIENTS SET BIRTH = '" + newClient.getBirthDate() +
"' WHERE ID = " + id1 + ";");
}
can be rewritten as
if (!oldClient.getName().equalsIgnoreCase(newClient.getName()) ||
!oldClient.getBirthDate().equalsIgnoreCase(newClient.getBirthDate())) {
stmt.executeUpdate("UPDATE CLIENTS SET NAME = '" + newClient.getName() +
"', BIRTH = '" + newClient.getBirthDate() +
"' WHERE ID = " + id1 + ";");
}
This will perform better because it executes one SQL statement instead of two. The fact that you are possibly setting two columns when only one needs to be set is probably of little consequence, compared with that.
Notes:
If you try to "optimize" the number of columns set, the code is more complicated; see Tim's answer.
This should probably be done with a PreparedStatement and statement parameters to avoid SQL injection. If you follow the above pattern, the changes needed to use a PreparedStatement are straight forward.
First, you can use one query to update every fields :
"UPDATE CLIENTES SET DATA_NASCI "
+ "MORADA = '" + clienteNew.getMorada() + "'"
+ "PAIS = '" + clienteNew.getPais() + "'"
+ "NACIONALIDADE = '" + clienteNew.getNacionalidade() + "'"
+ "BI = '" + clienteNew.getBI() + "'"
+ "TIPO_IDENT = '" + clienteNew.getTipoIndentificaçao() + "'"
+ "WHERE ID = " + id1 + ";"
Please use a PreparedStatement instead of this, this would be much safer !
All you have to do is check if only one field have changed (to prevent the transaction doing nothing) using a condition check each field :
if (!clienteOld.getNome().equalsIgnoreCase(clienteNew.getNome()))
|| (clienteOld.getDataNascimento().equalsIgnoreCase(clienteNew.getDataNascimento()))
|| (!clienteOld.getMorada().equalsIgnoreCase(clienteNew.getMorada()))
|| (!clienteOld.getPais().equalsIgnoreCase(clienteNew.getPais()))
|| (!clienteOld.getNacionalidade().equalsIgnoreCase(clienteNew.getNacionalidade()))
|| (!clienteOld.getBI().equalsIgnoreCase(clienteNew.getBI()))
|| (!clienteOld.getTipoIndentificaçao().equalsIgnoreCase(clienteNew.getTipoIndentificaçao()))
This can be a bit verbose ... so why not reduce this code a bit using Stream and some function references to compare and build a map of value to update :
First, the class Bean for our example :
class Bean {
String firstname, lastname;
public Bean(String firstname, String lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
}
Then, let's create a mapping of Column name and Function, the function will allow us to use the getters of Bean :
Map<String, Function<Bean, String>> functions = new HashMap<>();
functions.put("FIRSTNAME", Bean::getFirstname);
functions.put("LASTNAME", Bean::getLastname);
Then, using final instance (to be used in a Predicate)
final Bean clienteNew = new Bean("Foo", "Bar");
final Bean clienteOld = new Bean("Foo", "Boo");
Map<String, String> values = functions.entrySet()
.stream()
//filter only the value that changed between clienteOld and clienteNew
.filter(entry -> !entry.getValue().apply(clienteOld).equals(entry.getValue().apply(clienteNew)))
//then collect the map `name -> new value`
.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().apply(clienteNew)));
System.out.println(values);
{LASTNAME=Bar}
This will give you a Map<String, String> that can be used to create a PreparedStatement with only the column we want/need to edit.
If you have a new field, just need to add the mapping in the functions map and you are good to go. (this become a bit more complex with primitive type...)

Sql update query with Single quotes

I am using hibernate application in java to retrieve and update database.
During updating a table,i forming an sql query as follows,
String qry = "UPDATE " + entity + " SET " + htmlColumn + " ='"+value+"' WHERE " + id + " = " + primaryId;
where value is a html string which contains single quotes sometimes.
How to escape ignore/escape the single quotes and update the table successfully
Thanks
use PreparedStatement for this
String qry = "UPDATE " + entity +
" SET " + htmlColumn + " = ? " +
"WHERE " + id + " = ?";
PreparedStatement pstmt = con.prepareStatement(qry);
pstmt.setString(1, value);
pstmt.setInt(2, primaryId);
pstmt.executeUpdate();
PreparedStatement
Don't set values directly.
currentSession()
.createQuery("UPDATE " + entity + " SET " + htmlColumn +
" = :value WHERE " + id + " :id")
.setParameter("value", value).setParameter(":id",id).executeUpdate();
You can replace the single quote with a double single quote. value.replace("'","''"); but you will need to cater for more than just that because your value can easily allow for SQL Injection if it is not properly catered for.
You can use preparedstatement as :
String query= "UPDATE " + entity + " SET " + htmlColumn + " =? WHERE " + id + " = " + primaryId;
PreparedStatement ptmt = con.prepareStatement(query);
ptmt.setString(1, value);

How correctly address to specific column in Cursor?

Lets assume, that we have some 2 tables in SQLite: TBL_PRODUCT and TBL_PRODUCT_ALIASES. Now, I want to query some data from joined two tables:
String sql = "SELECT " + TBL_PRODUCT + "." + C_PROD_PKEY_ID + ", " + TBL_PRODUCT_ALIASES + "." + C_PROD_ALIASES_PKEY_ID +
" FROM " + TBL_PRODUCT + " LEFT JOIN " + TBL_PRODUCT_ALIASES + " ON " + TBL_PRODUCT + "." + C_PROD_PKEY_ID + " = " + TBL_PRODUCT_ALIASES + "." + C_PROD_ALIASES_PKEY_ID +
" WHERE " + C_PROD_SERVER_ID + " = ? LIMIT 1";
Cursor cursor = SQLiteDataHelper.getInstance().rawQuery(sql, new String[] {"" + js_CartProduct.getLong("prod_id")});
Thats works great without any problem. And then I want to acquire some data from the returned cursor:
if (cursor.getCount() > 0) {
cursor.moveToFirst();
Long prodId = cursor.getLong(cursor.getColumnIndexOrThrow(TBL_PRODUCT + "." + C_PROD_PKEY_ID));
//... Some other code
}
Now, here is the problem: C_PROD_PKEY_ID and C_PROD_ALIASES_PKEY_ID are in the real world the same Strings: "_id". And as the result getLong() returns long not from the needed column of cursor.
How should I correctly address to the needed column? Are there other methods besides using AS in sql query OR/AND using definite numbers in cursor.getLong(0) instead of cursor.getLong(cursor.getColumnIndexOrThrow(TBL_PRODUCT + "." + C_PROD_PKEY_ID))?
Update:
cursor.getColumnNames() returns this: [_id, _id].

java jdbc connection - result set output problems

I am currently trying to implement a jdbc connection that returns all the data in a table when i "search" for anything that matches the input with '%input%'.
eg ResultSet rs4 = stm4.executeQuery("select imageTime from image_data where imageName like '%" + value3 + "%' or imageTime like '%" + value3 + "%' or imageLocation like '" + value3 + "'" );
i am trying to return ALL the rows in the result set as search results.
but if i have Resultset.next commanded when there is no more rows to go to it
causes the following results sets to all null,....
if anything id love a method to output the entire result set, thanks.
EDIT
editing the question: to be more direct; i need a way to get every piece of data from each row in each containing column of the result set. so i can output it.
This is my attempt of this below.
rs4 = a Resultset as declared below.
here is my code;
if(name_time_location == 1)
{
String value3=searchInput.getText();//Sets the search Input as value3
// selecting the cominbation from table, that match input options
try{
con = DriverManager.getConnection("jdbc:mysql:blah blah");
// Query the database for the correct username and passord
Statement stm3 = con.createStatement();
Statement stm4 = con.createStatement();
Statement stm5 = con.createStatement();
//queries database for password from input username
ResultSet rs3 = stm3.executeQuery("select imageName from image_data where imageName like '%" + value3 + "%' or imageTime like '%" + value3 + "%' or imageLocation like '" + value3 + "'" );
//ResultSetMetaData rsmd = rs3.getMetaData();
//stm3.setFetchSize(5);
//rs3.last();
//int numberOfRows = rs3.getRow();
//String[] resultList;
//resultList = new String[numberOfRows];
// Fetch each row from the result set
rs3.beforeFirst();
while(rs3.next())
{
imageSearchResult1 = rs3.getString(1);
rs3.next();
imageSearchResult11 = rs4.getString(1);
rs3.next();
imageSearchResult12 = rs4.getString(1);
rs3.next();
imageSearchResult13 = rs4.getString(1);
rs3.next();
imageSearchResult14 = rs4.getString(1);
}rs3.close();
}catch (Exception e)
{
//System.out.println("Exception: " + e + "");
}
System.out.println("Search Results: \nName: " + imageSearchResult1 + " Time stamp: " + imageSearchResult2 + " Location: " + imageSearchResult3 + "\n" +
"Name: " + imageSearchResult11 + " Time stamp: " + imageSearchResult21 + " Location: " + imageSearchResult31 + "\n" +
"Name: " + imageSearchResult12 + " Time stamp: " + imageSearchResult22 + " Location: " + imageSearchResult32 + "\n" +
"Name: " + imageSearchResult13 + " Time stamp: " + imageSearchResult23 + " Location: " + imageSearchResult33 + "\n" +
"Name: " + imageSearchResult14 + " Time stamp: " + imageSearchResult24 + " Location: " + imageSearchResult34 + "\n" );
I think you can achieve the same thing by modifying the query and instead of creating 3 queries, get the 3 values in the same query as:
select imageName,imageLocation,imageTime from .....
Then use this query to generate the ResultSet and get the three values as rs.getType(1),rs.getType(2),rs.getType(3).
In the same while(rs.next()) loop, you can print the data that you want to print.

Categories

Resources