Insert list <string> into database using Java - java

I want to insert list of string into database so usually we will store the string directly into the database by either using a prepared statement or a batch statement. Now I want to insert list of string into a database, so I have used a prepared statement.
List<String> Account_Number = Files.lines(Paths.get("D:\\PDFTOEXCEL\\Extractionfrompdf.txt"))
.filter(s -> s.contains(arra.get(7)))
.map(s -> s.split(":")[1].trim())
.collect(Collectors.toList());
System.out.println(Account_Number);
try {
Connection conn = PDFTOEXCEL.getConnection();
PreparedStatement stmt = conn.prepareStatement("insert into client_info values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
stmt.setString(1, Account_Number);
int k = stmt.executeUpdate();
I have about 31 columns in my database. Just for showing I have posted only one in this code. All are in the list of the string only.

Have you tried to set the parameters one by one? Something like this:
int size = Account_Number.size();
for (int i = 1; i <= size; i++) {
stmt.setString(i, Account_Number.get(i-1));
}

Related

How sql works and why this result is returned?

Hi I'm using preparedStatement in Java to execute query in DB.
The table:
When it comes to update, delete and insert it's all fine, however when it comes to select( ex. I've done "SELECT ?,?,?,?,? from person" and set strings afterwards) and the following result is returned:
I'm assuming that because it's the strings that are replacing ? so it did not come out as expected:(please correct me if it's wrong)
Expected sql: "SELECT no,name,tel,birthday,address FROM person"
Actual sql: "SELECT \"no\",\"name\",\"birthday\",\"address\" FROM person"
I've tested the second one in in Navicat:
I'd like to understand that why executing this query statement would return a result like this?
If it would help here's Java code:
// Data Assist Object
public class DAO {
static String jdbcurl;
static String username;
static String password;
static{
try {
Class.forName("com.mysql.jdbc.Driver");
ResourceBundle rb = ResourceBundle.getBundle("db");
jdbcurl = rb.getString("jdbcurl");
username = rb.getString("username");
password = rb.getString("password");
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
}
// for insert, delete and update
public int modify(String sql, String[] args){
int x=0;
try(Connection con = DriverManager.getConnection( jdbcurl,username ,password);
PreparedStatement ps = con.prepareStatement(sql);){
for (int i = 0; i < args.length; i++) {
ps.setString(i+1, args[i]);
}
x =ps.executeUpdate();
System.out.println(x);
}catch(SQLException e){
e.printStackTrace();
}
return x;
}
// for select
public List<Map<String,String>> query(String sql, String[] params){
List<Map<String,String>> resList = new ArrayList<>();
try(Connection con = DriverManager.getConnection( jdbcurl,username ,password);
PreparedStatement ps = con.prepareStatement(sql);){
for (int i = 0; i < params.length; i++) {
ps.setString(i+1, params[i]);
}
try(ResultSet res =ps.executeQuery();){
ResultSetMetaData mdata = res.getMetaData();
int num = mdata.getColumnCount();
while(res.next()){
HashMap<String,String> data = new HashMap<>();
for (int i = 1; i <= num; i++) {
String result = res.getString(i);
String columnName = mdata.getColumnName(i);
data.put(columnName,result);
}
resList.add(data);
}
}
}catch(Exception e){
e.printStackTrace();
}
return resList;
}
public static void main(String[] args) throws SQLException {
DAO dao = new DAO();
String sql = "insert into person(name,tel,birthday,address) values(?,?,?,?)";
sql = "select ?,?,?,?,? from person";
List<Map<String,String>> res = dao.query(sql, new String[]{"no","name","tel","birthday","address"});
for(Map m:res){
System.out.print("no: "+m.get("no")+",");
System.out.print("name: "+m.get("name")+",");
System.out.print("tel: "+m.get("tel")+",");
System.out.print("birthday: "+m.get("birthday")+",");
System.out.println("address: "+m.get("address"));
}
}
}
Thanks for any help.
SQL basically works on a show me these columns where this criteria is true basis.
In the statement:
"SELECT \"no\",\"name\",\"birthday\",\"address\" FROM person"
You're getting
SELECT "no", "name", "birthday", "address" FROM person
when it actually hits the database. The "" operator creates a string in SQL. In plain English, that means that you're telling the database to return that specified set of strings for each row in person where the criteria you listed is met.
Since you didn't list a where clause, all rows are true by default so you get one row of strings for every single row in the person table. The first query is the same thing, but instead of directly passing the strings, you're adding them in as bind variables.
If you actually want to see the values in the table, write the query without the "'s
SELECT no, name, birthday, address FROM person
Unless otherwise specified, bind functions generally pass the value as a string. Which is why the query behaved the way it did. I don't recommend using bind variables in the select clause. That's a strange practice.
Edit:
As Adrian pointed out in the comments, " denotes columns in SQL. My apologies for not catching that. I assume that you meant to use the ' operator which actually denotes strings.
If not, something else is going on here entirely.
For the select you use the question marks in the WHERE clause, not where you list the fields you need as output.
Replace
sql = "select ?,?,?,?,? from person";
with
sql = "select no,name,tel,birthday,address from person";
For this particular query there is no binding to do. It will retrieve all the records from the table.

Efficient way to select data with a single condition

Is there an efficient way to obtain a list (preferably an array, a ResultSet will do) to SELECT a lot of rows.
For example:
Connection con = DriverManager.getConnection(host,username,password);
String sql = "SELECT * FROM table_name WHERE food = ? AND expiration > ?";
PreparedStatement stmt = con.prepareStatement(sql);
Using the above code, I want to get all the food from a given array that isn't expired.
String[] foodList = {"banana","apple","orange",...}
where the expiration date is a constant date (lets say 3 days ago). However, the way I have it is that the String and PreparedStatement are in a for loop that loop the number of foods in the array to individually check the expiration date. This creates a lot of ResultSets after I execute each individually.
Most SQL Databases support a IN (list) expression. This is roughly equivalent to providing a or expression:
SELECT id FROM table WHERE food IN ('Apple', 'Banana') AND exp < ?
is similar to
SELECT id FROM table WHERE (food = 'Apple' or food = 'Banana') AND exp < ?
In both cases some RDBMS can optimize it.
However first of all there is a limitation in the number of list items you can specify in the IN or number of characters you can use in the statement. So if your list can be variable long you need to be prepared to run multiple statements.
Secondly you cannot* set a array as an argument to a PreparedStatement and expect it to work with IN.
Unfortunately in plain JDBC all you can do is to concatenate a String. This is frowned upon, but there is no good alternative (unless you want to do something like giving the list of foods as a single list and use a "instring" expression).
Make sure to add as many ? (but not too many) as you expect parameters and then set them in the IN:
String[] foods = ...;
int remain = foods.length;
int start = 0;
while(remain > 0)
{ if (remain >= 100)
executeBatch(foods, start, 100); start+=100; remain-=100;
else if (remain >= 30)
executeBatch(foods, start, 30); start+=30; remain-=30;
else {
executeBatch(foods, start, 1); start+=1; remain-=1;
}
}
void executeBatch(String[] f, int off, int len)
{
StringBuilder sqlBuf = StringBuilder("... IN(");
for(int i=0;i<len;i++) {
sqlBuf.append((i!=0)?",?":"?");
}
String sql = sqlBuf.append(") AND exp < ?").toString();
PreparedStatement ps = c.prepareStatement(sql);
for(int i=0;i<foods.length;i++)
ps.setString(i+1, foods[i+off]);
ps.setTimestamp(foods.length+1, now);
....
}
This avoids to generate a lot of different SQL statement to compile. (Only 100,30 or 1 ?)). You can use the same logic for the OR case.
* not to be confused with ARRAY database type.
Probably not the most elegant solution, and you won't get any performance benefit from the prepared statement (but you will get parameter binding):
StringBuilder sql = new StringBuilder("SELECT * FROM table_name WHERE expiration > ? AND food IN (");
for (int i = 0; i < foodList.length; i++) {
if (i > 0) {
sql.append(',');
}
sql.append('?');
}
sql.append(")");
Connection con = DriverManager.getConnection(host, username, password);
PreparedStatement stmt = con.prepareStatement(sql.toString());
stmt.setDate(1, expirationDate);
for (int i = 0; i < foodList.length; i++) {
stmt.setString(i + 2, foodList[i]);
}
ResultSet rs = stmt.executeQuery();
/* ... Do Stuff ... */

How to pass a List of Integer value with PreparedStatement

I try to write a code for make a SELECT on MySql DB like this
SELECT MESE,IMPORTO,ANNO FROM VISTASTATISTICHEMENSILI WHERE ANNO in(?)
So, I would like to pass a list of Integer value like this:
PreparedStatement stmt = db.prepareStatement(queryDettaglio);
Integer[] myArr = new Integer[2];
myArr[0] = 1;
myArr[1] = 2;
stmt.setArray(1, db.createArrayOf("INTEGER", myArr));
ResultSet rs = stmt.executeQuery();
So, when I try to run this code I have this error:
DEBUG [AWT-EventQueue-0] (MyLog4J.java:45) - java.sql.SQLFeatureNotSupportedException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:310)
at com.mysql.jdbc.SQLError.notImplemented(SQLError.java:1332)
at com.mysql.jdbc.JDBC4Connection.createArrayOf(JDBC4Connection.java:58)
When I fix it?
Reguards
You can not pass an array to a ? in a prepared statement. The correct way to do it and avoid all chance of injection attack is like this:
StringBuilder idList = new StringBuilder()
for (int id : myArr) {
if (idList.length() > 0) {
idList.append(",");
}
idList.append("?");
}
PreparedStatement ps = con.prepareStement("SELECT MESE,IMPORTO,ANNO FROM VISTASTATISTICHEMENSILI WHERE ANNO in("+idList+");
for (int i = 0; i < myArr.length; i++) {
ps.setInt(i+1,myArr[i]);
}
Basically you are building a prepared statement with the right number of ? marks and then setting the parameters in.
Because myArr is declared as an Integer[] array, you can also just do this:
StringBuilder idList = new StringBuilder()
for (int id : myArr) {
if (idList.length() > 0) {
idList.append(",");
}
idList.append(id);
}
Statement stmt = con.createStatement();
stmt.executeQuery("SELECT MESE,IMPORTO,ANNO FROM VISTASTATISTICHEMENSILI WHERE ANNO in("+idList+");
There is no issue with injection because the integers can't possibly have injected characters (if they did, they wouldn't be integers)
Try binding n integers manually inside for loop.
Before that you should create ?,?,...,? pattern in sql.
Good luck.
import org.apache.commons.lang3.StringUtils;
/*
* example: for n=4 creates pattern: ?,?,?,?
*/
public String createInListPattern(int n) {
return StringUtils.repeat("?", ",", n);
}
public void doSelect(Integer[] myArr, Connection conn) {
int size = myArr.length;
String sql = "SELECT MESE,... FROM TABLE WHERE ANNO in ("
+ createInListPattern(size) + ")";
// be sure to properly handle sql exceptions
PreparedStatement stmt = conn.prepareStatement(sql);
// bind parameters
for (int i = 0; i < size; i++) {
stmt.setInt(i + 1, myArr[i]);
}
// execute query
ResultSet rs = stmt.executeQuery();
}

Passing an array to SELECT * FROM table WHERE country IN (?...)

Is there a way to pass an array of strings for a "WHERE country IN (...)" query?
something like this:
String[] countries = {"France", "Switzerland"};
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM table WHERE country IN (?...)");
pstmt.setStringArray(1, countries);
pstmt.executeQuery();
an ugly workaround would be to create the query based on the size of the array
String[] countries = {"France", "Switzerland"};
if (countries.size() == 0) { return null; }
String query = "SELECT * FROM table WHERE country IN (?";
for (int i = 1; i < countries.size; i++) { query += ", ?"; }
PreparedStatement pstmt = con.prepareStatement(query);
for (int i = 0; i < countries.size; i++) { pstmt.setString(1+i, countries[i]); }
pstmt.executeQuery();
but this looks really ugly.
any idea?
No, it's not possible. ORMs like Hibernate or wrapper APIs like Spring JDBC allows doing that. But with plain JDBC, you must do it yourself.
I think the work around would be formulating the entire query string at runtime and using a Statement object instead of PreparedStatement.
No way to try this.See here to other ways.But there is one exception, if you use oracle database then you can try this
If your database engine support IN (subquery), you can create a view or memory table to do it.

Inserting an Array of Characters into DB

I want to insert a 2 dimensional array into a DB table. Is there any way to insert these values into DB with a single INSERT statement rather than using multiple INSERT statements? These multiple statements create a tendency for DB connection pool issues and can create a latency in the application.
String[][] a = new String[10][2];
for(int i =0;i<10;i++)
{
st.executeUpdate("Insert into sap_details VALUES a[i][0],a[i][1]);
}
What happens here is there are effectively 10 INSERT statements being called for each row. I don't want it to; it should happen with only one INSERT statement.
Is there any way to do that?
Use JDBC Batch Updates? Using prepared statements should also help.
Example
String[][] a = new String[10][2];
PreparedStatement pst = con.prepareStatement("INSERT INTO sap_details VALUES (?,?)");
for (int i = 0; i < 10; i++) {
pst.setString(1, a[i][0]);
pst.setString(2, a[i][1]);
pst.addBatch();
}
int[] results = pst.executeBatch();
With MySQL, something like this should do the trick, perfectly fine , Oracle won't like it. This feature is supported by DB2, SQL Server (since version 10.0 - i.e. 2008), PostgreSQL (since version 8.2), MySQL, and H2.
String[][] a = new String[10][2];
StringBuilder sb = new StringBuilder("Insert into sap_details (a,b) VALUES ");
for(int i =0;i<a.length;i++){
sb.append("(\'");
sb.append(a[i][0]);
sb.append("\',\'");
sb.append(a[i][1]);
sb.append("\')");
if(i < a.length -1 )
sb.append(",");
}
st.executeUpdate(sb.toString());

Categories

Resources