Prepare statement inside a loop - java

I trying execute a query inside a loop.I am tryning this code :
public List<Products> DisplayProducts(String []a)
{
ResultSet rs = null;
List<Products> Data=null;
try
{
for(int i=0;i<a.length;i++)
{
String query = "select * from products where Brand=?";
PreparedStatement stmt=DataBaseConnection.DBConn.getConnection().prepareStatement(query);
stmt.setString(1, a[i]);
rs=stmt.executeQuery();
}
if(rs.next())
{
rs.beforeFirst();
Data=new ArrayList<Products>();
while(rs.next())
{
Products p=new Products();
p.setTitle(rs.getString(2));
p.setCategory(rs.getString(3));
p.setSubCategory(rs.getString(4));
p.setSubCategoryTwo(rs.getString(5));
p.setPrice(rs.getInt(6));
p.setFlavour(rs.getString(7));
p.setImage(rs.getString(8));
p.setBrand(rs.getString(9));
p.setInstock(rs.getString(10));
p.setInstockQty(rs.getInt(11));
Data.add(p);
}
}
return Data;
}
catch(Exception e)
{
System.out.println(e.getStackTrace());
return null;
}
}
I have a jsp page where I have Checkboxes and I am displaying multiple products on this page. I am sorting this products by BRANDS. User selects Brand by checking checkbox.
I am passing the value of checkbox to a servlet and on that servlet calling function Display Products:
String arr[]=request.getParameterValues("On");
List<Products> Data=new SessionBeanClass().DisplayProducts(arr);
Please tell me how do I execute this and get the result ?

I suppose you need to return the list of all products with the checkbox ticked. In that case i suppose you have a logic error here. This method only returns the last Product record.
Instead of looping through different id you could use 'IN' clause and return all at once. There are many differet ways to achieve IN clause. The one given below is a simple alternative. You could check for various operations in http://www.journaldev.com/2521/jdbc-preparedstatement-in-clause-alternative-approaches or http://www.javaranch.com/journal/200510/Journal200510.jsp#a2
In addition to that try following java naming conventions and clean up connections using finally
Try
public List<Products> DisplayProducts(String[] a) {
ResultSet rs;
List<Products> data;
PreparedStatement stmt;
try {
StringBuilder param = new StringBuilder();
for(String str : a){
param.append("'").append(str).append("', ");
}
String query = "select * from products where Brand in (" + param.substring(0, param.length() - 2) + ")";
stmt = DataBaseConnection.DBConn.getConnection().prepareStatement(query);
rs = stmt.executeQuery();
if (rs != null) {
data = new ArrayList<Products>();
while (rs.next()) {
Products p = new Products();
p.setTitle(rs.getString(2));
p.setCategory(rs.getString(3));
p.setSubCategory(rs.getString(4));
p.setSubCategoryTwo(rs.getString(5));
p.setPrice(rs.getInt(6));
p.setFlavour(rs.getString(7));
p.setImage(rs.getString(8));
p.setBrand(rs.getString(9));
p.setInstock(rs.getString(10));
p.setInstockQty(rs.getInt(11));
data.add(p);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
stmt.close();
}
return data;
}
Explanation as per comment
Ok. I suppose your idea here is to pass a set of brand names say adidas, nike, etc.. and select all the product details. So you need to do something like select * from products where Brand in ('adidas', 'nike'). This will give you all the products. So for this you pass the selected brand names as a string array. So what i did was to get the values from array and format it and make it as argument for IN clause. So of IN clause it needs comma separated values. Since its a Sting we need to give single quote ' as well. So from an array [adidas, nike] i need to construct 'adidas', 'nike'. That is what done in the for loop, appending ' and , (comma). So after for loop we'll have an additional comma and space at the end (e.g. 'adidas', 'nike', ). In order to remove this i remove the last two charaters by taking substring as param.substring(0, param.length() - 2). This is fed to the query and retrieve the result.

Related

Java and Kotlin interoperability, managing data using Koltin Lambda?

So essentially, I am using java to obtain information, and then I am using Kotlin to manage the information. So what I have done so far is, I have stored my information into a ArrayList called tableData in java, I store all my elements into this list (I should have used a better name here) and then returned the list. My java code:
public static ArrayList<String> readAllData () {
//Connecting to database
Connection con = DbConnection.connect();
//Preparing statement
PreparedStatement ps = null;
//result set declaration
ResultSet rs = null;
//tableData String array
ArrayList<String> tableData = new ArrayList<String>();
try {
//Database initialization
String sql = "SELECT * FROM ProjectInfo";
ps = con.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
//for each iteration store the data into variable a from column projectName
String a = rs.getString("projectName");
//print out each element
//System.out.println("a = " + a);
tableData.add(a);
}
//other catch exceptions
} catch (SQLException e) {
System.out.println(e.toString());
} finally {
try {
rs.close();
ps.close();
con.close();
} catch (SQLException e){
System.out.println(e.toString());
}
}
//System.out.println(tableData);
//return all the data that has been stored into this array
return tableData;
}
In Kotlin, I created a property class called GettingData and passed one parameter projectName: ArrayList<String>. Then i moved onto actually printing out the data
class GettingData(var projectName: ArrayList<String>) {
}
fun ManageData() {
var arrayData = listOf<GettingData>(GettingData(DbConnection.readAllData()))
var projectNameData = arrayData.map {it.projectName}
for (projectName in projectNameData) {
println(projectName)
}
}
All my elements are printed out, however I cannot use the filter functions to call specific elements from the arrayList? I want to be able to call every element and print them out in a alphabetical order? I tried filter, sortedWith and find functions but I cannot seem to get it working. How can I achieve this?
I think your question boils down to wanting to print a list of strings in alphabetical order.
You can use the sorted() function:
for (projectName in projectNameData.sorted()) {
println(projectName)
}

Getting inserted (or existing) ids with executeBatch()

I am trying to insert some words to database and return newly inserted id or existing id if the word is already in the database.
I found that I can do this using PreparedStatement and including Statement.RETURN_GENERATED_KEYS. But PreparedStatement is terribly slow. I need to insert like 5000 words at once. Another way I could achieve it by running individual query in for loop:
public ArrayList<Integer> addWords(ArrayList<String[]> allTermsForTag) {
ArrayList ids = new ArrayList<Integer>();
ResultSet rs = null;
try{
Statement st = connection.createStatement();
for (String[] articleTerms: allTermsForTag) {
for(String term: articleTerms) {
String query = "WITH a AS (INSERT INTO tag (name) SELECT '"+term+"' WHERE NOT EXISTS (SELECT name FROM tag WHERE name = '"+term+"') " +
"RETURNING id) SELECT id FROM a UNION SELECT id FROM tag WHERE name = '"+term+"'";
rs = st.executeQuery(query);
while (rs.next())
{
int id = rs.getInt(1);
ids.add(id);
System.out.printf("id: "+id);
}
}
}
rs.close();
st.close();
}catch(SQLException e){
System.out.println("SQL exception was raised while performing SELECT: "+e);
}
return ids;
}
This does what I need nicely, but this is too slow as well.
Another method that I wrote uses executeBatch(), however, it does not return ids:
public ArrayList<Integer> addWords(ArrayList<String[]> allTermsForTag){
ResultSet rs = null;
ArrayList ids = new ArrayList<Integer>();
try{
Statement st = connection.createStatement();
for (String[] articleTerms: allTermsForTag) {
for(String term: articleTerms) {
String query = "WITH a AS (INSERT INTO tag (name) SELECT '"+term+"' WHERE NOT EXISTS (SELECT name FROM tag WHERE name = '"+term+"') " +
"RETURNING id) SELECT id FROM a UNION SELECT id FROM tag WHERE name = '"+term+"'";
st.addBatch(query);
}
st.executeBatch();
rs = st.getGeneratedKeys();
while (rs.next()) {
int id = rs.getInt(1);
ids.add(id);
}
}
st.close();
return ids;
}catch (SQLException e){
System.out.println("SQL exception was raised while performing batch INSERT: "+e.getNextException());
System.out.println("dub");
}
return null;
}
So the question is - how to get ids when using executeBatch() or if this is not possible, how to approach this problem? I need it to work as fast as possible, because there will be a lot of INSERT operations with large amount of data.
Thank you!
Set set = new HashSet();
try {
PreparedStatement ps = cn.prepareStatement("delete from myTable where... ",
Statement.RETURN_GENERATED_KEYS);
ps.setInt(1,200);
ps.setInt(2,262);
ps.setString(3, "108gf99");
ps.addBatch();
ps.setInt(1,200);
ps.setInt(2,250);
ps.setString(3, "hgfha");
ps.addBatch();
ps.executeBatch();
ResultSet rs = ps.getGeneratedKeys();
while (rs.next()){
set.addAll(Collections.singleton(rs.getLong(1)));
}
System.out.println(set);
} catch (SQLException e) {
e.printStackTrace();
}
executeBatch can return generated keys in the latest PgJDBC versions. See issue 195 and pull 204. You must use the prepareStatement variant that takes a String[] of returned column names.
However... take a step back here. The solution isn't loops. The solution is almost never loops.
In this case, you should almost certainly use COPY via the PgJDBC CopyManager API to COPY data into a TEMPORARY table. Then do an INSERT INTO ... SELECT ... RETURNING ... to insert the temp table's contents into the final table and return any generated fields. You can also do a SELECT to join on the temp table to return any that already exist. This is basically a bulk upsert or closely related bulk insert-if-not-exists.
If for some reason you can't do that, the next-best option is probably multi-valued INSERTs with large VALUES lists, but this requires some ugly dynamic SQL. Since you need existing values if the row already exists you'll probably need a writeable CTE too. So really, just use COPY and a query to do the table merge.

Store rows of resultset in array of strings

I want to count the numbers of entries in resultset and then store these values in an array and pass this array to create a graph.
ResultSet rs = stmt.executeQuery( "SELECT distinct "+jTextField.getText()+" as
call from tablename"); // this statement will select the unique entries in a
particular column provided by jtextfield
int count=0;
while(rs.next())
{ ++count; } // This will count the number of entries in the result set.
Now I want to store the values of result set in an array of string. I used the following code
String[] row = new String[count];
while(rs.next())
{
for (int i=0; i <columnCount ; i++)
{
row[i] = rs.getString(i + 1);
}
}
Error : Invalid Descriptor Index.
Please suggest how to copy the result of resultset in array.
For example if I enter priority in jTextField , the result set will contain
priority1
priority2
priority3
In your first while loop you read all the entries in the ResultSet, so when executing the second while loop there's nothing else to read. Also, the index of ResultSet#getXxx starts at 1, not at 0. Also, since you don't know the amount of rows that you will read, it will be better using a List backed by ArrayList instead.
Considering these, your code should look like:
ResultSet rs = stmt.executeQuery( "SELECT distinct "+jTextField.getText()+
" as call from tablename");
List<String> results = new ArrayList<String>();
while(rs.next()) {
results.add(rs.getString(1));
}
Based in your comment, I extended the sample:
public List<String> yourRandomQuery(String columnName) {
Connection con = null;
ResultSet rs = null;
List<String> results = new ArrayList<String>();
try {
String baseQuery = "SELECT DISTINCT %s AS call FROM tablename";
con = ...; //retrieve your connection
ResultSet rs = stmt.executeQuery(String.format(baseQuery, columnName));
while(rs.next()) {
results.add(rs.getString(1));
}
} catch (SQLException e) {
//handle your exception
e.printStacktrace(System.out);
} finally {
closeResource(rs);
closeResource(con);
}
return results;
}
//both Connection and ResultSet interfaces extends from AutoCloseable interface
public void closeResource(AutoCloseable ac) {
try {
if (ac != null) {
ac.close();
}
} catch (Exception e) {
//handle this exception as well...
}
}
public void someMethod() {
//retrieve the results from database
List<String> results = yourRandomQuery(jTextField.getText());
//consume the results as you wish
//basic example: printing them in the console
for(String result : results) {
System.out.println(result);
}
}
Try this
ResultSet rs = stmt.executeQuery( "SELECT distinct "+jTextField.getText()+" as
call from tablename");
List<String> list=new ArrayList<>();
while(rs.next())
{
list.add(rs.getString(1));
}
Why not just create a HashSet<String> and write into that. Note that HashSet is unordered, just like your query. By using a collection that is of arbitrary size you don't need to determine the require dsize in advance.

Storing Result set into an array

i know this should be simpel and im probably staring straight at the problem but once again im stuck and need the help of the code gurus.
im trying too take one row from a column in jdbc, and put them in an array.
i do this as follows:
public void fillContactList()
{
createConnection();
try
{
Statement stmt = conn.createStatement();
ResultSet namesList = stmt.executeQuery("SELECT name FROM Users");
try
{
while (namesList.next())
{
contactListNames[1] = namesList.getString(1);
System.out.println("" + contactListNames[1]);
}
}
catch(SQLException q)
{
}
conn.commit();
stmt.close();
conn.close();
}
catch(SQLException e)
{
}
creatConnection is an already defined method that does what it obviously does.
i creat my result set
while theres another one,
i store the string of that column into an array.
then print it out for good measure. too make sure its there.
the problem is that its storing the entire column into contactListNames[1]
i wanted to make it store column1 row 1 into [1]
then column 1 row 2 into [2]
i know i could do this with a loop. but i dont know too take only one row at a time from a single column. any ideas?
p.s ive read the api, i jsut cant see anything that fits.
You should use an ArrayList which provides all the logic to automatically extend the array.
List rowValues = new ArrayList();
while (namesList.next()) {
rowValues.add(namesList.getString(1));
}
// You can then put this back into an array if necessary
contactListNames = (String[]) rowValues.toArray(new String[rowValues.size()]);
Did you mean something like:
int i = 0;
ResultSet rs = stmt.executeQuery("select name from users");
while (rs.next()) {
String name = rs.getString("name");
names[i++] = name;
}

How to check if resultset has one row or more?

How to check if resultset has one row or more with JDBC?
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
boolean isMoreThanOneRow = rs.first() && rs.next();
You didn't ask this one, but you may need it:
boolean isEmpty = ! rs.first();
Normally, we don't need the row count because we use a WHILE loop to iterate through the result set instead of a FOR loop:
ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1");
while (rs.next()) {
// retrieve and print the values for the current row
int i = rs.getInt("a");
String s = rs.getString("b");
float f = rs.getFloat("c");
System.out.println("ROW = " + i + " " + s + " " + f);
}
However, in some cases, you might want to window the results, and you need the record count ahead of time to display to the user something like Row 1 to 10 of 100. You can do a separate query with SELECT COUNT(*) first, to get the record count, but note that the count is only approximate, since rows can be added or removed between the time it takes to execute the two queries.
Sample from ResultSet Overview
There are many options, and since you don't provide more context the only thing left is to guess. My answers are sorted by complexity and performance ascending order.
Just run select count(1) FROM ... and get the answer. You'd have to run another query that actually selects and returns the data.
Iterate with rs.next() and count until you're happy. Then if you still need the actual data re-run same query.
If your driver supports backwards iteration, go for rs.next() couple of times and then rewind back with rs.previous().
You don't need JDBC for this. The normal idiom is to collect all results in a collection and make use of the collection methods, such as List#size().
List<Item> items = itemDAO.list();
if (items.isEmpty()) {
// It is empty!
if (items.size() == 1) {
// It has only one row!
} else {
// It has more than one row!
}
where the list() method look like something:
public List<Item> list() throws SQLException {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
List<Item> items = new ArrayList<Item>();
try {
connection = database.getConnection();
statement = connection.createStatement();
resultSet = statement.executeQuery(SQL_LIST);
while (resultSet.next()) {
Item item = new Item();
item.setId(resultSet.getLong("id"));
item.setName(resultSet.getString("name"));
// ...
items.add(item);
}
} finally {
if (resultSet != null) try { resultSet.close(); } catch (SQLException logOrIgnore) {}
if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
}
return items;
}
If you want to make sure that there is exactly one row, you can ensure that the first row is the last:
ResultSet rs = stmt.executeQuery("SELECT a FROM Table1 WHERE b=10");
if (rs.isBeforeFirst() && rs.next() && rs.isFirst() && rs.isLast()) {
// Logic for where there's exactly 1 row
Long valA = rs.getLong("a");
// ...
}
else {
// More that one row or 0 rows returned.
// ..
}
My no-brainer suggestion: Fetch the first result row, and then try to fetch the next. If the attempt is successful, you have more than one row.
If there is more than one row and you want to process that data, you'll need to either cache the stuff from the first row, or use a scrollable result set so you can seek back to the top before going through the results.
You can also ask SQL directly for this information by doing a SELECT COUNT(*) on the rest of your query; the result will be 0, 1 or more depending on how many rows the rest of the query would return. That's pretty easy to implement but involves two queries to the DB, assuming you're going to want to read and process the actual query next.
This implementation allows you to check for whether result of the query is empty or not at the cost of duplicating some lines.
ResultSet result = stmt.executeQuery("SELECT * FROM Table");
if(result.next()) {
// Duplicate the code which should be pasted inside while
System.out.println(result.getInt(1));
System.out.println(result.getString(2));
while(result.next()){
System.out.println(result.getInt(1));
System.out.println(result.getString(2));
}
}else{
System.out.println("Query result is empty");
}
Drawbacks:
In this implementation a portion of the code will be duplicated.
You cannot know how many lines are present in the result.
Get the Row Count using ResultSetMetaData class.
From your code u can create ResultSetMetaData like :
ResultSetMetaData rsmd = resultSet.getMetaData(); //get ResultSetMetaData
rsmd.getColumnCount(); // get row count from resultsetmetadata

Categories