I am trying to get values from MySQL db using a query which gets values from a multiple select. The problem is that I am using StringBuilder to create the query based on the values I am getting. If you see the Where clause used why me, every time a new variable is fetched a comma is added in the end.
How do I remove the last comma added as it is giving me an error in the sql query. Will appreciate any help.
String[] stat = req.getParameterValues("status");
StringBuilder sb = new StringBuilder(200);
if (stat != null) {
for (int i = 0; i < stat.length; i++) {
sb.append("'" + stat[i] + "',");
}
String app = "WHERE status in (" + sb.toString() + ")";
String sqlquery = "SELECT * FROM Table " + app + ";";
}
Result Query:
SELECT * FROM Table
WHERE status in ('Deployed','PendingDisposal','Available','Reserved','Broken',);
I want to get rid of the last comma after 'Broken'
Your problem is with comma in the end, you can append your Strings like this :
String del = "";
for (int i = 0; i < stat.length; i++) {
sb.append(del).append("'" + stat[i] + "'");
del = ",";
}
But in fact this is not really good idea to use this way, because it can cause SQL Injection or syntax error, you have to use PreparedStatement for example :
for (int i = 0; i < stat.length; i++) {
sb.append(del).append("?");
del = ",";
}
try (PreparedStatement ps = connection.prepareStatement(sb) {
for (int i = 0; i < stat.length; i++) {
ps.setString(i, stat[i]);
}
ResultSet result = preparedStatement.executeQuery();//get results
...
}
You can join a string array with commas using Java 8 streams:
String joined = Arrays.asList(stat).stream()
.map(s -> "'" + s + "'")
.collect(Collectors.joining(", "));
But note that joining strings like this is a really bad idea: you are vulnerable to SQL injection attacks, e.g. if one of the element of stat is something like:
'); DROP TABLES Table; --
You are better off building the query using a PreparedStatement. See this question.
Need to update your for loop where you need to append element from array till its second last element and append last element of the array outside the loop.
for(int i=0;i<stat.length-1;i++){ // loop till second last element
sb.append("'"+stat[i]+"',"); //appends , at end
}
sb.append("'"+stat[stat.length-1]+"'"); // append last element
You can use deleteChartAt method:
sb.deleteCharAt(sb.length()-1);
For example:
String[] stat = req.getParameterValues("status");
StringBuilder sb = new StringBuilder(200);
if(stat!=null) {
for(int i=0;i<stat.length;i++){
sb.append("'"+stat[i]+"',");
}
sb.deleteCharAt(sb.length()-1); //---------> This will remove the last comma
String app = "WHERE status in ("+sb.toString()+")";
String sqlquery = "SELECT * FROM Table "+app+";";
}
try something this.
for(int i=0;i<stat.length;i++){
sb.append("'"+stat[i]+"'");
if(i!=stat.length-1){
sb.append(",");
}
}
try
String app = "WHERE status in ("+sb.substring(0, sb.length()-2)+")";
Related
I'm beginning to learn sql and java and I have a problem.
The logic for the code is:
The first part of the sql statement should be "a.stdn_code_ts" and as more elements (in this case student code) are included, I need to concatenate with and OR-Statement.
student codes could be a single value or a range, say for example: '567777' is valid as well as '567777-876677'.
If it is single value, just add "=" then the student code. In the example if the user entered '567777' then the query should be something like "a.stdnt_code_ts = '567777'"
If it is a range, add the first student code then "BETWEEN" second code. I.e.: if the user entered '567777-876677', the query should be "a.stdnt_code_ts BETWEEN '567777' AND '876677'".
and as I mentioned above, if there are 2 or more student codes the query should be concatenated with an "OR a.stdnt_code_ts" then checks again if it is a single value or a range.
I already have this code and got stuck:
private void formatStudentCode(Connection connection) throws Exception {
studentCode = "a.stdnt_code_ts ";
for(int i=0; i < stdntCode.size(); i++) {
if (stdntCode.get(i).indexOf("-")==-1) {
studentCode += "= '" + stdntCode.get(i) + "'";
}
else {
String [] range=stdntCode.get(i).split("-");
studentCode += "BETWEEN '" + range[0] + "' AND '" + range[1] +
"'";
}
}
}
First, this code is incomplete, so I'll need to make some guesses. But let's try.
Let's fix the loop first:
String sql = "SELECT * FROM students";
List<String> terms = new ArrayList<>();
List<String> arguments = new ArrayList<>();
// Don't need index here, for each loop is better
for (String code : codes) {
// No need for IndexOf
if (code.contains("-")) {
terms.add("stdnt_code_ts between ? and ?");
String[] split = code.split("-");
arguments.add(split[0]);
arguments.add(split[1]);
}
else {
// Don't concatenate SQL query parameters
terms.add("stdnt_code_ts = ?");
arguments.add(code);
}
}
Now to put our OR:
if (terms.size() > 0) {
sql += " WHERE " + Strings.join(terms, " OR ");
}
Now to add actual parameters for each question mark:
PreparedStatement preStmt = conn.prepareStatement(sql);
int count = 0;
for (String code : arguments) {
preStmt.setString(++count, code);
}
And finally to execute the query:
ResultSet rs = preStmt.executeQuery();
Note that I'm not running this code, so I may miss a line or two, but that's the general idea of how it should be done correctly.
What I want is inserting datas into array String[],and then print the array values.
the returning String[] type method is
public String[] getRequirementDocIDofProject(String testprojectName)
throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
String req_doc_ids[] = null;
String str_sqlQuery = "select * from req_specs INNER JOIN nodes_hierarchy nh " +
"on nh.id=req_specs.testproject_id " +
"INNER JOIN requirements reqs " +
"on req_specs.id =reqs.srs_id where nh.name='" + testprojectName + "'";
int count = 0;
int n = 0;
initDB();
resultSet = statement.executeQuery(str_sqlQuery);
while (resultSet.next()){
count = Integer.parseInt(resultSet.getString(1));
}
req_doc_ids = new String[count];
resultSet = statement.executeQuery(str_sqlQuery);
while (resultSet.next()) {
req_doc_ids[n] = resultSet.getString("req_doc_id");
System.out.println("REQID=" + req_doc_ids[n]);
n++;
}
close();
System.out.println("n==" + n);
return req_doc_ids;
}
the calling method code is
DBConnection dbcon = new DBConnection();
String req_doc_ids[] = dbcon.getRequirementDocIDofProject("XXXX");
System.out.println(req_doc_ids.length);
the print message in Console is
REQID=TECH-6104
REQID=TECH-6686
REQID=TECH-5391
REQID=TECH-5965
REQID=TECH-6530
REQID=TECH-6729
REQID=TECH-7082
REQID=TECH-7107
REQID=TECH-7184
n==9
7166
why req_doc_ids.length 's value is 7166 rather than 9
7166 comes from the 1-th column of the result set - it's the value in the last row.
while(resultSet.next()){
count=Integer.parseInt(resultSet.getString(1));
}
Instead, you perhaps meant:
while(resultSet.next()){
count++;
}
Mind you, this is an unnecessarily inefficient way to create the array. Use a List instead; or, use the method on the result set API to get the number of rows directly.
Your main issue has already been clarified by Andy and this answer is just an extension to help you with your current code.
Couple of improvements possible in your code.
Prefer using PreparedStatement instead of Statement which is not safe and may be at risk to SQL Injection attack as already mentioned by Jon Skeet.
Why to run a db query twice which potentially could be a heavy query just to find out the number of records to correctly initialize your String array.
Use List<String> to store whatever number of rows you get and finally convert the list to array like shown in below code.
Get rid of so many unneeded variables and so many lines of code to make your code appear crisp and clear.
You may try changing your method to this one,
public String[] getRequirementDocIDofProject(String testprojectName)
throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException {
List<String> reqDocIdList = new ArrayList<String>();
String str_sqlQuery = "select * from req_specs INNER JOIN nodes_hierarchy nh " +
"on nh.id=req_specs.testproject_id " +
"INNER JOIN requirements reqs " +
"on req_specs.id =reqs.srs_id where nh.name='" + testprojectName + "'";
initDB();
resultSet = statement.executeQuery(str_sqlQuery);
while (resultSet.next()){
System.out.println("REQID=" + resultSet.getString("req_doc_id"));
reqDocIdList.add(resultSet.getString("req_doc_id"));
}
close();
System.out.println("n==" + reqDocIdList.size());
return reqDocIdList.toArray(new String[reqDocIdList.size()]);
}
When i run the below program
package com.util;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws Exception {
ArrayList<String> list_of_symbols = new ArrayList<String>();
list_of_symbols.add("ABB");
list_of_symbols.add("ACC");
list_of_symbols.add("SBIN");
StringBuilder sb_builder = new StringBuilder();
for (int i = 0; i < list_of_symbols.size(); i++) {
sb_builder.append(list_of_symbols.get(i) + ",");
}
String sql = "Select * from data where symbol_name IN ("
+ sb_builder.deleteCharAt(sb_builder.length() - 1).toString()
+ ")";
System.out.println(sql);
}
}
The Result of SQL IS
Select * from data where symbol_name IN (ABB,ACC,SBIN)
Where as the expected result should be
Select * from data where symbol_name IN ('ABB','ACC','SBIN')
Could you please let me know how can i keep Quotes so that it becomes valid SQL
Don't use string concatenation to fill in SQL parameters. It's error-prone. Instead, build the SQL with as many ? as you need, and then use a PreparedStatement and as many setString(x, theString) as you need to fill in the ?.
In your case, it would look roughly like this:
package com.util;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) throws Exception {
ArrayList<String> list_of_symbols = new ArrayList<String>();
list_of_symbols.add("ABB");
list_of_symbols.add("ACC");
list_of_symbols.add("SBIN");
// Build the statement
StringBuilder sql = new StringBuilder(200);
sql.append("Select * from data where symbol_name IN (");
for (int i = 0; i < list_of_symbols.size(); i++) {
sql.append(i == 0 ? "?" : ", ?");
}
sql.append(')');
// Build the PreparedStatement and fill in the parameters
PreparedStatement ps = someConnection.prepareStatement(sql.toString());
for (int i = 0; i < list_of_symbols.size(); i++) {
ps.setString(i + 1, list_of_symbols.get(i));
}
// Do it
ResultSet rs = ps.executeQuery();
}
}
(This is un-optimized, and dashed off. Some editing is likely required.)
This site has a good explanation of why using string concat for parameters is a bad idea, as well as practical examples of how to do things properly in many languages, including Java.
As you know the number of values in your list I'd suggest to put in one ? per IN value and make it a PreparedStatement.
Then simply do
ps.setString (n, nthString);
In a loop for 1..n parameters and your driver will handle proper escaping.
Like this:
List<String> list_of_symbols = new ArrayList<String>();
list_of_symbols.add("ABB");
list_of_symbols.add("ACC");
list_of_symbols.add("SBIN");
StringJoiner join = new StringJoiner(",",
"Select * from data where symbol_name IN (", ")");
for (int i = 0; i < list_of_symbols.size(); i++) {
join.add("?");
}
PreparedStatement ps = aConnection.prepareStatement(join.toString());
for (int i = 0; i < list_of_symbols.size(); i++) {
ps.setString(i+1, list_of_symbols.get(i));
}
When making your list, use this:
sb_builder.append("'"+list_of_symbols.get(i) + "',");
Notice the ' on the string. This works for simple cases only, where strings do not have ' and you're not worried with SQL Injection. For more complex cases, used PreparedStatements and add a list of ?. Then replace the ? with the Strings you want to use.
I have a dynamic number of data values in an array fetched from an HTML form.
Now I want to update my table with these data.
The column names are column1 , column2 ... and so on;
I have data in the array[] and number of columns to update in unumber
I am using this code but its not working.
P.S: I am new to coding so it might be naive.
for(int i=1; i<=unumber; i++)
{
String username = "someuser";
String column = "column" + Integer.toString(i);
PreparedStatement pr = null;
String query1 = "update table1 set (?) = (?) where username = (?)";
pr = con.prepareStatement(query1);
pr.setString(1, column);
pr.setString(2, array[i]);
pr.setString(3, someuser);
int s = pr.executeUpdate();
}
AFAIK, you can't use "prepared statements" for this. You can resolve it by performing the insertion in the query yourself:
String query1 = "update table1 set "+column+" = ? where username = ?";
pr = con.prepareStatement(query1);
pr.setString(1, array[i]);
pr.setString(2, someuser);
But be aware of sql injection. You better check whether the possible values of column can't be altered. Validate all input that leads to determining the column name.
Make sure a user can't specify the column his/herself: otherwise one could for instance set the column to password and set a password for some user. And then login with that password. Or one could try to set the column to '; drop table foo; select * where x
PreparedStatments can only bind values, not syntactic elements or object names, like columns, so this approach won't work. You'll have to fall back to string manipulation:
for(int i=0; i<unumber; i++) {
String username = "someuser";
String column = "column" + Integer.toString(i);;
PreparedStatement pr = null;
String query1 = "update table1 set " + column + " = (?) where username = (?)";
pr = con.prepareStatement(query1);
pr.setString(1, column);
pr.setString(2, someuser);
int s = pr.executeUpdate();
}
Moreover, since you're updating several columns with the same where clause, you could loop over the columns and construct just one update statement. It will force you to have two loops (one for constructing the query and one for binding the values once the query is prepared), but it should still be considerably faster, as you're accessing the database only once instead of N times:
String username = "someuser";
StringBuilder sql = new StringBuilder("update table1 set ");
for(int i=0; i < unumber; i++) {
sql.append("column")
.append(i).
.append(" = ?");
if (i != (unumber - 1)) {
sql.append(", ");
}
}
sql.append("where username = (?)");
PreparedStatement pr = con.prepareStatement(sql.toString());
for(int i = 0; i < unumber; i++) {
pr.setString(i, array[i]);
}
pr.setString(unumber, someuser);
int s = pr.executeUpdate();
I'm trying to store rows from a table into an array. I can get the first result and store that but I cannot seem to be able to store any of the other data.
This is the code I've written
try
{
test = "select * from Arsenal order by 'MatchNumber' ASC";
rs = st.executeQuery(test);
while (rs.next())
{
//This retrieves each row of Arsenal table and adds it to an array in the Team Results class.
matchno = rs.getString("MatchNumber");
hometeam = rs.getString("HomeTeam");
awayteam = rs.getString("AwayTeam");
homegoals = rs.getString("HomeGoals");
awaygoals = rs.getString("AwayGoals");
result = rs.getString("Result");
teams = (matchno + "," + hometeam + "," + awayteam + "," + homegoals + "," + awaygoals + "," + result); // Takes all the variables containging a single customers information and puts it into a string, seperated by commas.
TeamResults.add(matchno,hometeam,awayteam,homegoals,awaygoals,result);
}
}
Any idea where I'm going wrong?
Change the while-condition to hasNext() and use next() inside of the loop to move the database cursor forward.
Try to use this method bellow :
public void SelectData(String sqlcounter ,String sql){
try {
RsCounter=stmt.executeQuery(sqlcounter);
System.out.println(sqlcounter);
while(RsCounter.next()){
countrow=RsCounter.getInt("COUNTR");
System.out.println(countrow+"\n");
}
System.out.println(sql);
RsSelecting = stmt.executeQuery(sql);
data=new String[countrow][RsSelecting.getMetaData().getColumnCount()];
header= new String[RsSelecting.getMetaData().getColumnCount()];
i=0;
while(RsSelecting.next()){
for(j=0;j<RsSelecting.getMetaData().getColumnCount();j++){
data[i][j]=(RsSelecting.getString(j+1));
header[j]=RsSelecting.getMetaData().getColumnName(j+1);
System.out.print(data[i][j]+"\n");
}
i++;
}
i=j=0;
} catch (SQLException ex) {
ex.printStackTrace();
Logger.getLogger(Connect.class.getName()).log(Level.SEVERE, null, ex);
}
}
where
sqlcounter ="select COUNT(*) as COUNTR from Arsenal order by 'MatchNumber' ASC";
and
sql ="select * from Arsenal order by 'MatchNumber' ASC";
Verify the column names once. Sometimes ALIAS doesn't work out, I am not sure why.
Get the meta data from the result set:
ResultSetMetaData metaData = resultSet.getMetaData();
int size = metaData.getColumnCount();
for (int i = 0; i < size; i ++)
System.out.println(metaData.getColumnName(i);
Also just for performance, list out the column names instead of using * in the SELECT query. Also, you can take a look at com.sun.rowset.CachedRowSetImpl. It's used like:
CachedRowSetImpl crs = new CachedRowSetImpl();
crs.populate(resultSet);
I think it also implements CachedRowSet, but I am not entirely sure.