I am currently writing a simple Java app that reads information from an XLS file and then enters it in the database. Since that XLS does have duplicated records, I do a simple check if the entry in the XLS file already exists in the database. Here is my code:
public static void addResult(ArrayList<ArrayList<String>> listResults)
{
try
{
openDatabase();
stmt = c.createStatement();
for (int i = 0; i < listResults.size(); i++)
{
PreparedStatement stm = c.prepareStatement("SELECT player_name FROM results WHERE player_name=?;");
stm.setString(1, listResults.get(i).get(ReadResultsFile.NAME));
System.out.println(stm);
ResultSet rs = stm.executeQuery();
if (rs.getRow() <= 0)
{
String typeOfPlay = new String();
if (listResults.get(i).get(ReadResultsFile.TYPE).equals("Simple"))
{
typeOfPlay = "single";
}
else if (listResults.get(i).get(ReadResultsFile.TYPE).equals("Double"))
{
typeOfPlay = "double";
}
stm = c.prepareStatement("INSERT INTO results (player_name, school_id, " + typeOfPlay + ", tournament_id) "
+ "VALUES(?,?,?,?);");
stm.setString(1, listResults.get(i).get(ReadResultsFile.NAME));
stm.setString(2, listResults.get(i).get(ReadResultsFile.SCHOOL_ID));
stm.setInt(3, Integer.parseInt(listResults.get(i).get(ReadResultsFile.SCORE)));
stm.setString(4, "1");
stm.executeUpdate();
}
else
{
String typeOfPlay = new String();
if (listResults.get(i).get(ReadResultsFile.TYPE).equals("Simple"))
{
typeOfPlay = "single";
}
else if (listResults.get(i).get(ReadResultsFile.TYPE).equals("Double"))
{
typeOfPlay = "double";
}
stm = c.prepareStatement("UPDATE results SET " + typeOfPlay + "=? WHERE player_name=?;");
stm.setString(1, typeOfPlay);
stm.setString(2, listResults.get(i).get(ReadResultsFile.SCORE));
stm.setString(1, listResults.get(i).get(ReadResultsFile.NAME));
System.out.println(stm);
stm.executeUpdate();
}
}
closeDatabase();
}
catch (Exception e)
{
System.err.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(0);
}
}
The problem that arises is that the rs.getRow() function always returns -1. I tried running the SELECT query directly in the database tool and the query returns the player_name column if there is already a similar entry existing. It unfortunately do the same in Java.
I am unsure what to do at this point.
Thank you for any hint!
getRow will not work as per the javadocs
Retrieves the current row number. The first row is number 1, the second number 2, and so on.
and
A ResultSet cursor is initially positioned before the first row; the
first call to the method next makes the first row the current row
Usually use
while (rs.next ()) {....
Related
How to make this one work? Obviously I don't know some very basic staff about SQL queries inside other SQL queries in Java but searching around didn't help!
Thank you in advance
try (Connection con = L2DatabaseFactory.getInstance().getConnection())
{
PreparedStatement stm = con.prepareStatement("SELECT count,owner_id FROM items WHERE item_id=57 order by count desc limit 10");
ResultSet rSet = stm.executeQuery();
while (rSet.next())
{
int owner_id = rSet.getInt("owner_id");
int count = rSet.getInt("count");
if (count == 0)
{
continue;
}
PreparedStatement stm1 = con.prepareStatement("SELECT char_name,accesslevel,online FROM characters WHERE obj_Id=" + owner_id);
ResultSet rSet1 = stm1.executeQuery();
while (rSet1.next())
{
int accessLevel = rSet.getInt("accesslevel");
if (accessLevel > 0)
{
continue;
}
String pl = rSet.getString("char_name");
int online = rSet.getInt("online");
String status = online == 1 ? "<font color=\"00FF00\">Online</font>" : "<font color=\"FF0000\">Offline</font>";
sb.append("<tr><td>"+ pl +"</td><td>"+ count +"</td><td>"+ status +"</td></tr>");
}
}
}
catch (Exception e)
{
_log.log(Level.SEVERE, "Error", e);
}
It looks like you are trying to join two tables using Java code. This is not such a great idea and not good for performance. Let the database do the joins for you - it is an expert at that. Do not code "inner joins" in Java.
Apart from that: the prepared statements are not being closed and this will sooner or later cause you trouble with OS resources.
My suggestion would be to create one single query with an inner join or a select in statement and also close all prepared statements using try with resources. Something along these lines:
private String test() throws SQLException {
StringBuilder sb = new StringBuilder();
int count = 0;
try (Connection con = L2DatabaseFactory.getInstance().getConnection()) {
try (PreparedStatement stm1 = con.prepareStatement(
"SELECT char_name,accesslevel,online FROM characters WHERE obj_Id in (SELECT owner_id FROM items WHERE item_id=57 order by count desc limit 10)")) {
ResultSet rSet = stm1.executeQuery();
while (rSet.next()) {
count++;
int accessLevel = rSet.getInt("accesslevel");
if (accessLevel > 0) {
continue;
}
String pl = rSet.getString("char_name");
int online = rSet.getInt("online");
String status = online == 1 ? "<font color=\"00FF00\">Online</font>" : "<font color=\"FF0000\">Offline</font>";
sb.append("<tr><td>" + pl + "</td><td>" + count + "</td><td>" + status + "</td></tr>");
}
}
} catch (Exception e) {
Logger.getLogger("test").log(Level.SEVERE, "Error", e);
}
return sb.toString();
}
What should I need to pass to complete this method. The error is :
The method fireSelect(String, String[], String[]) in the type DBConnection is not applicable for the arguments (String).
This is the method :
public static ResultSet fireSelect(String query, String[] types,
String[] values) {
try {
PreparedStatement ps = getInstance().prepareStatement(query);
if (types != null) {
for (int i = 0; i < types.length; i++) {
if (types[i].equals("int"))
ps.setInt((i + 1), Integer.parseInt(values[i]));
else if (types[i].equals("string"))
ps.setString((i + 1), values[i]);
else if (types[i].equals("double"))
ps.setDouble((i + 1), Double.parseDouble(values[i]));
}
}
return ps.executeQuery();
} catch (Exception e) {
try {
connection = null;
if (cnt < 2) {
connection = getInstance();
cnt++;
fireSelect(query, types, values);
} else {
cnt = 0;
}
} catch (Exception ee) {
System.out.println("Exception :" + ee);
}
}
return null;
}
and this is I have use to pass during cal this method
ResultSet rs = DBConnection.fireSelect(
"select dealer_id,car_servicing,car_servicing,cost,features "
+ " from dealer_car,carservicing where "
+ "dealer_car.car_servicing=carservicing.car_servicing and dealer_id="
+ dealerId);
As your SQL doesn't expect any paramaters, you can simply do
ResultSet rs = DBConnection.fireSelect(sql, null, null);
It expects 3 arguments, and you provided only one.
Just call like,
ResultSet rs = DBConnection.fireSelect("Select Query", null, null);
You're missing String[] types and String[] values, you could pass it as null (in your case), should be better if you call it like follow:
String sql = "select dealer_id,car_servicing,car_servicing,cost,features from
dealer_car,carservicing where dealer_car.car_servicing=carservicing.car_servicing
and dealer_id=:dealer_id";
String[] types = new String[]{"int"}; //or maybe string?
String[] vals = new String[]{dealerId};
ResultSet rs = DBConnection.fireSelect(sql, types, vals);
you need to pass all 3 argumens to the function fireSelect()
Your SQL does'nt expect a paramter, it is build up by concatenation, what is not good. fireSelect seems to be e helper to use a prepared statement and you are avoiding this.
fireSelect("select * from ... where id=?", new String[]{"int"}, new String[]{"42"});
even this
fireSelect((String)null,(String[])null,(String[])null);
Your fireSelect method is expecting 3 arguments:
You can use something like:
ResultSet rs = DBConnection.fireSelect(
"select dealer_id,car_servicing,car_servicing,cost,features "
+ " from dealer_car,carservicing where "
+ " dealer_car.car_servicing=carservicing.car_servicing and dealer_id="
+ dealerId,
new String[]{"int"},
new String[]{dealerId});
I'm trying to code a system for a large IRC channel (Twitch Channel)
One of the things I'm trying to do is log every user and give them points for being in the chat. For all intents and purposes the chat is just a large IRC channel. I'm retrieving the users in a big list from the twitch API, I put all the usernames in a large Array and running the following timer with a while loop:
timer = new Timer(900000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
updating = true;
try {
Arraynumber = 0;
TwitchBot.getDate();
arrayused = false;
System.out.println("trying to save users if theres enough stuff");
while(Arraynumber < TwitchBot.words.length){
TwitchBot.CheckUpdateUserSQL(TwitchBot.words[Arraynumber]);
Arraynumber++;
System.out.println("updating database");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
As you can see it's a simple timer that picks the name from a String[] and runs every name through the script individually.
The updateuser looks like such:
public static void CheckUpdateUserSQL(String sqluser) throws ClassNotFoundException{
selectSQL(sqluser);
if (id == "thisuserdoesntexistforsure"){
InsertSQL(sqluser);
}
else{
int progress = CurrentTime - lastlogin;
int totalprogress = progress + totaltime;
if(progress < 60 && progress > 0){
c15 = null;
Statement stmt = null;
if(isonline == 1) {
coins = progress / 4;
}
else{
coins = progress / 5;
}
int coinsincrease = (int) Math.ceil(coins);
int coinstotal = coinsamount + coinsincrease;
Class.forName("org.sqlite.JDBC");
try {
c15 = DriverManager.getConnection("jdbc:sqlite:users.db");
c15.setAutoCommit(false);
stmt = c15.createStatement();
String sql = "UPDATE USERS set TOTALTIME = " + totalprogress + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql);
c15.commit();
String sql2 = "UPDATE USERS set LASTLOGIN = " + CurrentTime + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql2);
c15.commit();
String sql3 = "UPDATE USERS set TOTALCOIN = " + coinstotal + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql3);
c15.commit();
String sql4 = "UPDATE USERS set ISONLINE = 0 where NAME='" + sqluser + "';";
stmt.executeUpdate(sql4);
c15.commit();
stmt.close();
c15.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
Connection c = null;
Statement stmt = null;
try {
c = DriverManager.getConnection("jdbc:sqlite:users.db");
c.setAutoCommit(false);
stmt = c.createStatement();
String sql2 = "UPDATE USERS set LASTLOGIN = " + CurrentTime + " where NAME='" + sqluser + "';";
stmt.executeUpdate(sql2);
c.commit();
stmt.close();
c15.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
This code checks whether an user exists. (using the select method, which is as concise as I can get it, it only search for an username and returns the id, which will be 'thisuderdoesntexistforsure' if nothing returns)
If the user exists it will run the code to calculate their online time and the increase in online time and points since the last time they visited. Then updates the code. If they were not online or if the time somehow returns a negative value (or one that's too high) it will instead only update the timestamp and skip the rest of the updates. This makes sure that users who leave for a day don't just get 1.400 minutes of online time when they log on five minutes the next day.
Anyway. My question is; How can I trim it down? I'm running into an issue where it will take 6 minutes to update the entire userlist. having 2000 users online is not rare and it would take 2,000 loops through that while loop to update them all. The program is updating more often then not. I've tried cutting down the code to be as condensed as possible, but I have no idea where to start to speed things up.
Sorry if I'm coming over as moronic, I'm relatively new to SQL and this is my biggest project yet in JAVA.
You can use batching to perform your updates, but in your given code a simpler optimization would be to update the values with one update call (instead of 4). Also, you could use PreparedStatement and try-with-resources close. Something like,
public static void CheckUpdateUserSQL(String sqluser) throws ClassNotFoundException {
selectSQL(sqluser);
if (id.equals("thisuserdoesntexistforsure")) {
InsertSQL(sqluser);
} else {
String sql = "UPDATE USERS set TOTALTIME = ?, LASTLOGIN = ?, "
+ "TOTALCOIN = ?, ISONLINE = 0 where NAME = ?";
String sql2 = "UPDATE USERS set LASTLOGIN = ? where NAME=?";
int progress = CurrentTime - lastlogin;
int totalprogress = progress + totaltime;
if (progress < 60 && progress > 0) {
if (isonline == 1) {
coins = progress / 4;
} else {
coins = progress / 5;
}
int coinsincrease = (int) Math.ceil(coins);
int coinstotal = coinsamount + coinsincrease;
Class.forName("org.sqlite.JDBC");
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:users.db");
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, totalprogress);
ps.setInt(2, CurrentTime);
ps.setInt(3, coinstotal);
ps.setString(4, sqluser);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
} else {
Class.forName("org.sqlite.JDBC");
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:users.db");
PreparedStatement ps = conn.prepareStatement(sql2)) {
ps.setInt(1, CurrentTime);
ps.setString(2, sqluser);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
What you need is batchupdate. Some good tutorial can be found on the internet.
An example can be the following:
stm = db.prepareStatement("INSERT INTO ITEM (ID, TYPE, TITEL, UITGELEEND) VALUES (?, ?, ?, ?)");
db.setAutoCommit(false);
for (int n = 0; n < ItemLijst.getItems().size(); n++) {
Item huidigItem = ItemLijst.getItemObvIdx(n);
stm.setString(1, huidigItem.getID().toString());
stm.setString(2, huidigItem.getType().toString());
stm.setString(3, huidigItem.getTitel());
stm.setString(4,String.valueOf(huidigItem.isUitgeleend()));
stm.addBatch();
}
String SQL = "UPDATE Employees SET age = 35 " +
"WHERE id = 100";
// Add above SQL statement in the batch.
stm.addBatch(SQL);
stm.executeBatch();
db.commit();
Also try avoiding joining strings, instead use '?', otherwise it will be subjected to sql injection attacks.
http://tutorials.jenkov.com/jdbc/batchupdate.html
http://www.tutorialspoint.com/jdbc/jdbc-batch-processing.htm
i have a swing application which consists of a text box and a button.On entering the emp_id and clicking the button it connects to mysql and fetch all the rows corresponding to the emp_id entered in a table. my code is fetching only 1 row of the mysql data, even though there is 3 rows corresponding to the emp_id
my code is:
try {
Class.forName(driverName);
Connection con = DriverManager.getConnection(url, userName,password);
String sql = "select * from devices where emp_id = " + textvalue;
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
int i = 0;
if (rs.next()) {
asset_id = rs.getString("asset_id");
name = rs.getString("name");
project = rs.getString("project");
emp_id = rs.getString("emp_id");
emp_name = rs.getString("emp_name");
model.addRow(new Object[] { asset_id, name, project, emp_id,emp_name });
// i++;
}
if (i < 1) {
JOptionPane.showMessageDialog(null, "No Record Found", "Error",JOptionPane.ERROR_MESSAGE);
}
if (i == 1) {
System.out.println(i + " Record Found");
} else {
System.out.println(i + " Records Found");
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex.getMessage(), "Error",JOptionPane.ERROR_MESSAGE);
}
frame1.add(scroll);
frame1.setVisible(true);
frame1.setSize(400, 300);
you are fetching only first row.. fetch it in a loop
while(rs.next())
{
asset_id = rs.getString("asset_id");
name = rs.getString("name");
project = rs.getString("project");
emp_id = rs.getString("emp_id");
emp_name=rs.getString("emp_name");
model.addRow(new Object[]{asset_id, name, project, emp_id,emp_name});
//i++;
}
You get only one row from ResultSet :
if (rs.next()) {
asset_id = rs.getString("asset_id");
name = rs.getString("name");
project = rs.getString("project");
emp_id = rs.getString("emp_id");
emp_name = rs.getString("emp_name");
model.addRow(new Object[] { asset_id, name, project, emp_id,
emp_name });
// i++;
}
replace if with while, for getting all rows in loop.
For centring frame use frame.setLocationRelativeTo(null);.
According to docs
If the component is null, or the GraphicsConfiguration associated with this component is null, the window is placed in the center of the screen. The center point can be obtained with the GraphicsEnvironment.getCenterPoint method.
Also:
1) replace next code:
if (i == 1) {
System.out.println(i + " Record Found");
} else {
System.out.println(i + " Records Found");
}
with System.out.println(i + " Record Found"); because its code duplication.
2)Don't use setSize(...) use pack() method.
3)Call frame1.setVisible(true); in last line of construction or like next:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frame.setVisible(true);
}
});
The code below gets the information i require from my database but is not printing out all of the information. Firstly i know it is getting all of the correct information from the table because i have tried the query in sql developer.
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = getConnection();
String query = "SELECT menu.menu_id, menu_title, dish.dish_id, dish_name, dish_description, dish_price, menu.week_no "
+ "FROM menu, dish, menu_allocation "
+ "WHERE menu.active = '1' "
+ "AND menu.menu_id = menu_allocation.menu_id "
+ "AND dish.dish_id = menu_allocation.dish_id "
+ "AND menu.week_no IN (09, 10, 11)";
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
MenuList list = null;
while (rs.next()) {
list = new MenuList(rs);
System.out.println(rs.getRow());
}
for (int pos = 0; pos < list.size(); pos++) {
Menu menu = list.getMenuAt(pos);
System.out.println(menu.getDescription());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
}
}
}
The output from the terminal is as follows:
3 //Number of rows
Fish and Chips //3rd row
Chocolate Cake //2nd row
//Here should be 1st row
BUILD SUCCESSFUL (total time: 2 seconds)
Even though it says there are three rows it has only printed the two. Can anybody see if there is a problem with the above?
It's hard to be sure without seeing the code for the MenuList class but I don't think you need to loop over the ResultSet as MenuList does that for you.
As the MenuList constructor takes the ResultSet in rs as a parameter it probably loops over the ResultSet to create its entries. As you've already called rs.next() in the while of your loop the MenuList misses the first result.
I think you should replace all this:
MenuList list = null;
while (rs.next()) {
list = new MenuList(rs);
System.out.println(rs.getRow());
}
With:
MenuList list = new MenuList(rs);
I would suggest you use a debugger so you understand what your progam is doing.
You appear to be only keeping the last row loaded, so while you have 3 rows, you only keep the last. It appears you are getting two values from the last row.
public static void main(String[] args) {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = getConnection();
String query = "SELECT menu.menu_id, menu_title, dish.dish_id, dish_name, dish_description, dish_price, menu.week_no "
+ "FROM menu, dish, menu_allocation "
+ "WHERE menu.active = '1' "
+ "AND menu.menu_id = menu_allocation.menu_id "
+ "AND dish.dish_id = menu_allocation.dish_id "
+ "AND menu.week_no IN (09, 10, 11)";
stmt = conn.createStatement();
rs = stmt.executeQuery(query);
MenuList[3] list = null;
int idx = 0; //Add index
while (rs.next()) {
list[idx] = new MenuList(rs); //use index
idx++; //increment index
System.out.println(rs.getRow());
}
for (int pos = 0; pos < list.size(); pos++) {
Menu menu = list.getMenuAt(pos);//Don't know that
//get menu by index
System.out.println(menu.getDescription());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
}
}
}