SQL Update : WHERE clause error - java

I don't know whats wrong with this query :
SQL = "UPDATE "+ choosenClass +" SET COUNT = "+count+" WHERE NAME = "+names;
stmt2.executeUpdate( SQL );
Error :
java.sql.SQLSyntaxErrorException: Column 'RAMAYAH' is either not in any table in the FROM list or appears within a join specification and is outside the scope of the join specification or appears in a HAVING clause and is not in the GROUP BY list. If this is a CREATE or ALTER TABLE statement then 'RAMAYAH' is not a column in the target table.
It says Column RAMAYAH is not there but the string "RAMAYAH" itself is taken from the same table. Help Please.

Try to enclose the string into single quotes:
SQL = "UPDATE "+ choosenClass +" SET COUNT = "+count+" WHERE NAME = '"+names+"'";
stmt2.executeUpdate( SQL );

Apart from SQL-Injection vulnerability as mentioned by others in comment; your query has few more mistakes/issues.
You need to quote the filter value in WHERE condition WHERE NAME = "+names should be
WHERE NAME = '"+names+"'". Otherwise, your query will be formed like below and query engine will presume that there exist a column named RAMAYAH in your table in question.
UPDATE tab1 SET COUNT = 10 WHERE NAME = RAMAYAH;
Also, in your UPDATE statement, you have a column names COUNT which is a reserve word. You need to escape it to be in safe side.
If you are using mysql then use backtique
for sql-server use [] square bracket
for postgresql and oracle use "" double-quote

Related

Dynamic column name using prepared statement + sql query with variable containing 's

My query
attributes.replace(" ' ", "");
//also used SET "+attributes+"
String sql;
sql = "UPDATE diseaseinfo"
+ " SET ?=?"
+ "WHERE companyname = 'mycom' && diseaseName =?";
PreparedStatement preparedStmt = connects.prepareStatement(sql);
preparedStmt.setString(1, attributes);
preparedStmt.setString(2, attrData);
preparedStmt.setString(3, medname);
System.out.println(preparedStmt);
it is giving me an error because query set the column name in string so it become like this on causes
UPDATE diseaseinfo SET 'causes'='abc' WHERE companyname = 'mycom' and diseaseName ='fever'
and through this question I get to know that I can't add dynamic column by prepared statement: https://stackoverflow.com/a/3136049/7794329
Now, the real question comes up: suppose if I will use a simple update query like in this question: jdbc dymanic sql query with variable containg 's
It says you can't enter value with 's in your simple sql query because it will again make the query syntactical error for example :
SELECT * FROM diseaseinfo WHERE diseaseName = 'Adult Still's disease' AND name = 'add';
Here it wont execute because of ' 's on 'Adult Still's
Then it won't work with simple query. What should I do now? What to use? To set dynamic column with taking care of 's in the query.
I am not worried about SQL injection because i am working on local. And I just want my query to be executed.
Right. We can't supply identifiers as bind parameters. The name of the column has to be part of the SQL text.
We can dynamically incorporate the name of the column into the SQL text with something like this:
sql = "UPDATE diseaseinfo"
+ " SET `" + colname + "` = ?"
+ " WHERE companyname = 'mycom' AND diseaseName = ?";
And supply values for the two remaining bind parameters
preparedStmt.setString(1, attrData);
preparedStmt.setString(2, medname);
And you are absolutely correct about being concerned about SQL Injection.
Supplied as bind values, single quotes in the values of attrData and medname won't be an issue, in terms of SQL Injection.
But the example I've provided is vulnerable through incorporating the colname variable into the SQL text, if we don't have some guaranteed that colname is "safe" to include in the statement.
So we need to make the assignment of a value to colname "safe".
Several approaches we can use do that. The most secure would be a "whitelist" approach. The code can ensure that only specific allowed "safe" values get assigned to colname, before colname gets included into the SQL text.
As a simple example:
String colname;
if (attributes.equals("someexpectedvalue") {
colname = "columnname_to_be_used";
} else if (attributes.equals("someothervalid") {
colname = "valid_columname";
} else {
// unexpected/unsupported attributes value so
// handle condition or throw an exception
}
A more flexible approach is to ensure that a backtick character doesn't appear in colname. In the example, the value of colname is being escaped by enclosing it in backticks. So, as long as a backtick character doesn't appear in colname, we will prevent a supplied value from being interpreted as anything other than as an identifier.
For a more generic (and complicated) approach to using hardcoded backtick characters, we could consider making use the supportsQuotedIdentifiers and getIdentifierQuoteString methods of java.sql.DatabaseMetaData class.
(In the OP code, we don't see the datatype of contents of attributes. We see a call to a method named replace, and the arguments that are supplied to that. Assuming that attributes is a String, and that's supposed to be a column name, it's not at all clear why we would have "space single quote space" in the string, or why we need to remove that. Other than this mention, this answer doesn't address that.)

Need column names and column values from update sql before executing

I need to know the list of the column and values from the update sql using java. Code is to read a update query and take backup of the actual column values before executing the update sql. For this is need to know the column names. Please advise!
sql = update testenv.employee set gender = '2',StudentInd = '112233' where empID in (987987);
String criteriaQuery = resultset.getString("query"); // this is the update statement which is not constant and varies everytime.
String schema = StringUtils.substringBetween(criteriaQuery.toUpperCase(), "UPDATE ", ".").trim();
String table = StringUtils.substringBetween(criteriaQuery.toUpperCase(), ".", "SET").trim();
String columnName = StringUtils.substringBetween(criteriaQuery.toUpperCase(), "SET", "=").trim();
But columnName will not get the correct columns. Need to optimise the code such that i can get the entire column names from the update query.
If you're using JDBC, you can use the following:
ResultSetMetaData md = rs.getMetaData();
after getting the result set of your select statement.
http://www.roseindia.net/jdbc/jdbc-mysql/DiscriptionTable.shtml
Provides a clear example, the same applies for SQLServer databases and Oracle.

select column name from H2 with columns that have spaces

I am attempting to query from a tab delimited file with H2 and java. When I select * there are no problems, however, one of the columns has a space in the column name. When I try to query on just that column I get an exception:
Caused by: org.h2.jdbc.JdbcSQLException: Column "EXAMPLE" not found; SQL statement:
It appears as though it is not grabbing both words in the column name (Example ColumnName), but only grabbing the first.
This is what I have:
System.out.println( simpleJdbcTemplate.queryForList( "SELECT Example ColumnName FROM CSVREAD('" + fileName
+ "', null,'UTF-8', chr(9)) where send = 1;", new Object[] {} ) );
I'm guessing there is a special syntax to do this, but I can't seem to find it. I've tried enclosing the column name in: square brackets, single quotes, double quotes, tick marks all to no avail.
Is there a way to query H2 using columns that have spaces in the name?
According to the documentation, double quotes should do the trick.
Remember to escape them correctly in Java, i.e. to just store your column name in a String, use
String exampleColumnName = "\"Example ColumnName\"";
Also, note it is case sensitive, from the documentation:
Quoted names are case sensitive
You can also use brackets [] if you set "MODE=MSSQLServer" in your connection properties. Example:
SELECT * FROM [My Table]
The connection string would look something like this:
jdbc:h2:~/test;MODE=MSSQLServer

Oracle & java dynamic 'Order by' clause

I am trying to build a dynamic sql query in java (shown below)
sqlStr = "Select * " +
"from " + tableName
if(tableName!=null){
if(tableName.equals("Table1"){
sqlStr = sqlStr.concat("order by city desc");
}else if(tableName.equals("Table2"){
sqlStr = sqlStr.concat("order by country desc");
}else if(tableName.equals("Table3"){
sqlStr = sqlStr.concat("order by price desc");
}
}
Now what i would like to do is to add a final 'else' statement which would order the query based on whether the table contains a column named 'custID'. There will be several tables with that column so i want to sort the ones that have that column by custID. (Rather than having hundreds of additional if statements for each table that does have that column name.) Is this possible? i have seen people using the 'decode' function but i cant work out how to use it here.
Use DatabaseMetaData to get the table information.
You can use the getTablexxx() and getColumnxx() methods to get the table information.
Connection conn = DriverManager.getConnection(.....);
DatabaseMetaData dbmd = conn.getMetaData();
dbmd.getxxxx();
Note: you forgot space in your code before ORDER BY clause.
If you are happy with hardcoding things, a way to avoid multiple conditionals would be to store a list of all the tables that include custID.
private final static String tablesWithCustID = "/TableX/TableY/TableZ/";
...
if (tablesWithCustID.contains( tableName )) {
sqlStr = sqlStr.concat("order by custID")
}
You could use a List instead of a simple delimited string if you like.
Perhaps better, you could store a map with table names as the key, and the sort string as the value. Load it up once, then you don't need any conditional at all.
The most straight-forward way to do it is to read the column definitions from USER_TAB_COLUMNS or ALL_TAB_COLUMNS and check for the existence of a custID column. Without crazy PL/SQL tricks, you won't be able to solve this in SQL alone.
BTW, there is a " " missing between tableName and the order by clauses.
I understand that you're looking for a solution that can do this in one query, i.e. without running a separate metadata query beforehand.
Unfortunately, this won't be possible. The decode function can do some dynamic things with column values, but not with column name. And you're looking for a solution dynamically derive the column name.
An alternative might be to just add ORDER BY 1, 2. This is an old syntax that means order by the first and than by the second column. It might be a good solution if the custID column is the first column. Otherwise it at least gives you some sorting.
How about ArrayList.contains()?
You can create a list of tables which have that column, and just check for tables.contains(tablename) in the final if condition.

Variable column names using prepared statements

I was wondering if there was any way to specify returned column names using prepared statements.
I am using MySQL and Java.
When I try it:
String columnNames="d,e,f"; //Actually from the user...
String name = "some_table"; //From user...
String query = "SELECT a,b,c,? FROM " + name + " WHERE d=?";//...
stmt = conn.prepareStatement(query);
stmt.setString(1, columnNames);
stmt.setString(2, "x");
I get this type of statement (printing right before execution).
SELECT a,b,c,'d,e,f' FROM some_table WHERE d='x'
I would, however, like to see:
SELECT a,b,c,d,e,f FROM some_table WHERE d='x'
I know that I cannot do this for table names, as discussed
here, but was wondering if there was some way to do it for column names.
If there is not, then I will just have to try and make sure that I sanitize the input so it doesn't lead to SQL injection vulnerabilities.
This indicates a bad DB design. The user shouldn't need to know about the column names. Create a real DB column which holds those "column names" and store the data along it instead.
And any way, no, you cannot set column names as PreparedStatement values. You can only set column values as PreparedStatement values
If you'd like to continue in this direction, you need to sanitize the column names (to avoid SQL Injection) and concatenate/build the SQL string yourself. Quote the separate column names and use String#replace() to escape the same quote inside the column name.
Prepare a whitelist of allowed column names. Use the 'query' to look up in the whitelist to see if the column name is there. If not, reject the query.
For MySQL prepared statements with NodeJS (mysqljs/mysql), what you need to know is that ? is for values, but if you need to escape column names, table names etc, use ?? instead.
Something like this will work:
SELECT ??, ??, ?? FROM ?? WHERE ?? < ?
Set values to ['id', 'name', 'address', 'user', 'id', 100]
I think this case can't work because the whole point of the prepared statement is to prevent the user from putting in unescaped query bits - so you're always going to have the text quoted or escaped.
You'll need to sanitize this input in Java if you want to affect the query structure safely.
Use sql injection disadvantage of Statement Interface as advantage.
Ex:
st=conn.createStatement();
String columnName="name";
rs=st.executeQuery("select "+ columnName+" from ad_org ");
public void MethodName(String strFieldName1, String strFieldName2, String strTableName)
{
//Code to connect with database
String strSQLQuery=String.format("select %s, %s from %s", strFieldName, strFieldName2, strTableName);
st=conn.createStatement();
rs=st.executeQuery(strSQLQuery);
//rest code
}
Below is the solution in java.
String strSelectString = String.format("select %s, %s from %s", strFieldName, strFieldName2, strTableName);

Categories