Unexpected behaviour of SELECT query after UPDATE - java

Following is the logic in my java code :
con.setAutoCommit(false);
int starIndex = 0;
List Details = new ArrayList();
while (true) {
isRsEmpty = true;
String my_Query = "select * from x,y,z where"
+ " x.a = y.b"
+ " x.a = z.c"
+ "y.b = z.e"
+ " ORDER BY a ASC"
+ " limit 5"
+ " offset " + starIndex;
preparedStatement = con.prepareStatement(my_Query);
rs = preparedStatement.executeQuery();
while (rs.next()) {
isRsEmpty = false;
//Other processing steps
starIndex++;
Details.add(rs.getInt("id"));
}
if(isRsEmpty){
starIndex = 0;
}
Iterator itr = Details.iterator();
String updateTable = "UPDATE x SET status = ? where i = ? and j = ? and k = ?";
updatePreparedStatement = con.prepareStatement(updateTable);
while (itr.hasNext()) {
updatePreparedStatement.setInt(1, 1);
updatePreparedStatement.setString(2, "zzz");
updatePreparedStatement.setInt(3, 9);
updatePreparedStatement.setInt(4, 10);
updatePreparedStatement.addBatch();
}
updatePreparedStatement.executeBatch();
con.commit();
Details.clear();
}
The Problem :
I have 13 entries in my table which meets the select query.
When I first time run the query my Limit is 5 and Offset is 0 and I get
5 records correctly from the table and the selected 5 records are updated.
After doing the update to the table when the select query runs again it gives me 3 records.This is unexpected since I have more 8 records left in the table.Again the 3 records are updated.
Again when the select query runs it gives me 0 records.
Then again a select query runs which gives me 5 records and updates the 5 records.
I am not able to understand this behaviour. If I run my select query without update then it runs correctly which gives me 5,5,3 records , but with the above logic it gives me 5,3,0,5 records.
What is the problem here ?
Note : In the above program all the variables like PreparedStatement and other are declared correctly.
Thank you

Is there any chance you are missing "and" keyword between your conditions in the select query?
String my_Query = "select * from x,y,z where"
+ " x.a = y.b"
+ " AND x.a = z.c"
+ " AND y.b = z.e"
+ " ORDER BY a ASC"
+ " limit 5"
+ " offset " + starIndex;
I don't know if that would solve the problem but I find it weird that it works like this.

Related

PreparedStatement set Where clause [duplicate]

This question already has answers here:
How to use a tablename variable for a java prepared statement insert [duplicate]
(4 answers)
Closed 4 years ago.
I'm using PreparedStatement for a DELETE query.
My ps is configured as this
config.sql.statement.delete=DELETE FROM ? WHERE ?
Then in my Java code, I set values like this
ps.setString(1, schemaName == "F" ? "FUNDS" : "MANDATE" + "." + tableName);
ps.setString(2, whereClause);
The whereClause is set up as below
String whereClause = " ";
for (int m = 0; m < columns.size(); m++) {
String columnData = jsonObj.getString(columns.get(m));
log.info("Column Data for column " + columns.get(m) + " Value: " + columnData);
if (m == 0) {
whereClause = whereClause + columns.get(m) + " = " + "'" + columnData + "'";
} else {
whereClause = whereClause + " AND " + columns.get(m) + " = " + "'" + columnData + "'";
}
}
log.info("WHERE CLAUSE: " + whereClause);
whereClause is being logged as this:
WHERE CLAUSE: CLIENT_END_DT = '9998-12-31' AND CLIENT_START_DT = '2017-04-06' AND FUND_CODE = 'TEST_CODE'
ERROR that I got:
com.microsoft.sqlserver.jdbc.SQLServerException: An expression of non-boolean type specified in a context where a condition is expected, near '#P1'.
After google a bit, I noticed that it might be related to how I configure WHERE clause. Any exact problem with the way I use this ps?
With PreparedStatement you cannot use database object names i.e. table, columns as parameter.
In your sql query, use specific names for both table and columns, in order to avoid SQL injections.
DELETE FROM table_name WHERE column1 = ? and column2 = ?
Perhaps, you may use your custom placeholder for the same as work around, beware of SQL attacks !
config.sql.statement.delete=DELETE FROM $table WHERE $whereClause
Later build your sql as:
String sql = ...; /* your logic */
sql = sql.replace("$table",(schemaName == "F" ? "FUNDS" : "MANDATE" + "." + tableName));
sql = sql.replace("$whereClause",whereClause);
ps=conn.prepareStatement(sql);

MySQL JDBC Fail calculating row number

I have this select that works every time running in workbench but fails sometimes for the same arguments over jdbc. The problem is that sometimes, over JDBC, 'pos' value returns null. I Think that, for some reason, the #p as not started, but dont know how to fix.
SELECT t1.wId, t1.twId, t1.name, t1.timeout, t1.pos
FROM (
SELECT w.id AS wId, tw2.id AS twId, w.name AS name, tw2.timeout AS timeout, #p:=#p+1 AS pos
FROM timeout_workqueue tw1
INNER JOIN timeout_workqueue tw2
ON tw1.workqueue_id = tw2.workqueue_id
INNER JOIN workqueue w
ON tw1.workqueue_id = w.id
WHERE tw1.id = ?
ORDER BY tw2.id) t1, (SELECT #p:=1) c
WHERE t1.twId = ?;
The whole Java Code Are:
public TimeoutWorkqueueView getTimeoutWorkqueueView(Integer id) {
String sql = "SELECT t1.wId, t1.twId, t1.name, t1.timeout, t1.pos"
+ " FROM ("
+ " SELECT w.id AS wId, tw2.id AS twId, w.name AS name, tw2.timeout AS timeout, #p:=#p+1 AS pos"
+ " FROM timeout_workqueue tw1"
+ " INNER JOIN timeout_workqueue tw2"
+ " ON tw1.workqueue_id = tw2.workqueue_id"
+ " INNER JOIN workqueue w"
+ " ON tw1.workqueue_id = w.id"
+ " WHERE tw1.id = ?"
+ " ORDER BY tw2.id) t1, (SELECT #p:=1) c"
+ " WHERE t1.twId = ?";
return (TimeoutWorkqueueView) getJdbcTemplate().queryForObject(sql, new BeanPropertyRowMapper(TimeoutWorkqueueView.class), id, id);
}
Ok so the problem i can see here (please verify) is that you think you are running the query with parameter set to 1 to begin with.
However if you set #p = 1 -> this #p:=#p+1 will not evaluate to 1 any more.
Also assuming you have 20 rows, you run this query 20 times but on the last run it will return null because pos will be 21 and this does not exists.

Obtaining a count of data from one SQL table with a relationship to another and using this in java

I have 2 database tables for my program: GameInfo and Characters.
How this works is that a Game has 4 maps with different names and each character added to the game must be assigned any of the 4 maps. Now I have the sql statement which returns a result set named "Expr1001, of the number of characters on each map. I then need to add this information to a jTable and link up the corresponding amount of each characterson a map, with the mapname.
My ResultSet with the query which returns the amount of characters on each map:
ResultSet qs = dbm.queryDatabase("SELECT Expr1001 FROM (SELECT GameInfo.mapname, SUM(IIF(Map = GameInfo.mapname,1,0)) FROM (SELECT * FROM [Character] INNER JOIN Player ON Character.PlayerID=Player.[ID]) AS A RIGHT JOIN GameInfo ON A.Character.map = GameInfo.mapname GROUP BY GameInfo.mapname) AS [%$###_Alias]");
The whole method which gets the Game Info from the database from the GameInfo table, which comprises of a GameID and MapName only.
public Game[] getGameInfo(){
Game[] arr = null; //Creates an array of Games
try { //getting list from database
ResultSet rs = dbm.queryDatabase("Select Count(GameID) as NumGames from GameInfo" );
//While there are still more rows to read from the database.
rs.next();
int count = rs.getInt("NumGames");
arr = new Game[count];
String sql = "Select * from GameInfo";
// System.out.println(sql);
rs = dbm.queryDatabase(sql);
//Take the info from the current row
//Add the info to the array
ResultSet qs = dbm.queryDatabase("SELECT Expr1001 FROM (SELECT GameInfo.mapname, SUM(IIF(Map = GameInfo.mapname,1,0)) FROM (SELECT * FROM [Character] INNER JOIN Player ON Character.PlayerID=Player.[ID]) AS A RIGHT JOIN GameInfo ON A.Character.map = GameInfo.mapname GROUP BY GameInfo.mapname) AS [%$###_Alias]");
for(int i = 0; rs.next(); i++){
arr[i] = new Game(
rs.getInt("GameInfo.GameID"),
rs.getString("GameInfo.mapname"),
qs.getInt(i));
}//Creates a Game from the currently selected info
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Failed to get Games");
e.printStackTrace();
}
return arr;
}
}
The data is then added to the jTable which is on a Panel in the GameInfoPanel class:
public void refreshTable() {
//remove old stuff
refreshing = true;
Game[] arr = gim.getGameInfo();
DefaultTableModel model = (DefaultTableModel) GameInfoTable.getModel();
while (model.getRowCount() > 0) {
model.removeRow(0);
}
for (int i = 0; i < arr.length; i++) {
model.addRow(new Object[]{
arr[i].getNumberOfCharacters(),
arr[i].getID(),
arr[i].getMapName()});
}
refreshing = false;
//load new data from database using manager
}
I keep getting the error which points to the ResultSet qs line: "user lacks privilege or object not found: A.CHARACTER.MAP" when I try and run the program even though when I copy this statement into Microsoft Access and run it, it's fine.
Help please!
Thanks.
(I am still at school so not really a genius on this at all so please have mercy if I've done some stupid things)
Don't run a select count(*) first to get the number of games for allocating an array. Build you result in a List, which will auto-expand as needed. You can always convert the list to an array later, if needed.
Don't run two queries when one can do the job, especially when you already join to the table in question.
Your SQL is unreadable, so here it is in a more readable format:
String sql = "SELECT Expr1001" +
" FROM (SELECT GameInfo.mapname" +
", SUM(IIF(Map = GameInfo.mapname,1,0))" +
" FROM (SELECT *" +
" FROM [Character]" +
" INNER JOIN Player ON Character.PlayerID=Player.[ID]" +
") AS A" +
" RIGHT JOIN GameInfo ON A.Character.map = GameInfo.mapname" +
" GROUP BY GameInfo.mapname" +
") AS [%$###_Alias]";
The outer query does nothing. Get rid of it.
Don't SELECT *. Select the columns you want, i.e. Character.map.
Since you want GameID, add it to the GROUP BY.
Specify an alias for the SUM value.
public Game[] getGameInfo(){
String sql = " SELECT GameInfo.GameID" +
", GameInfo.mapname" +
", SUM(IIF(C.map = GameInfo.mapname,1,0)) AS CharacterCount" +
" FROM ( SELECT Character.map" +
" FROM [Character]" +
" JOIN Player ON Player.[ID] = Character.PlayerID" +
") C" +
" RIGHT JOIN GameInfo ON GameInfo.mapname = C.map" +
" GROUP BY GameInfo.GameID" +
", GameInfo.mapname";
try (ResultSet rs = dbm.queryDatabase(sql)) {
List<Game> games = new ArrayList<>();
while (rs.next())
games.add(new Game(rs.getInt("GameID"),
rs.getString("mapname"),
rs.getInt("CharacterCount")));
return games.toArray(new Game[games.size()]);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Failed to get Games");
e.printStackTrace();
return null;
}
}

JDBC PreparedStatemnt MySQLSyntaxErrorException

I have read previous questions related to my query.Tried making those changes in my existing code.But still getting this error.I have spent 3 hours resolving this,but not able to catch the bug.Please help me with it.
I am using PreparedStatement for sending SQL queries.Below is the query:
String getExistingFileEntry = "select * from test "
+ " where a = ? and b = ? and date < DATE_SUB(NOW(), INTERVAL 1 DAY)"
+ "order by id"
+ "limit 1";
PreparedStatement pstVerify = null;
pstVerify = con.prepareStatement(getExistingFileEntry);
pstVerify.setString(1, a);
pstVerify.setString(2, b);
ResultSet rsFirst =null;
String existingSum = null;
//execute select SQL statement
rsFirst = pstVerify.executeQuery();
Getting this error # rsFirst = pstVerify.executeQuery()
com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1' at line 1
I tried running this SQL query on workbench and returns the correct rows.
Can someone please point me where I am doing wrong?
Thanks!
check your spaces replace this
String getExistingFileEntry = "select * from test "
+ " where a = ? and b = ? and date < DATE_SUB(NOW(), INTERVAL 1 DAY)"
+ "order by id"
+ "limit 1";
by
String getExistingFileEntry = "select * from test "
+ " where a = ? and b = ? and date < DATE_SUB(NOW(), INTERVAL 1 DAY)"
+ " order by id"
+ " limit 1";

set max results in hibernate not working as per requirement

This is my query which is written using HQL. My requirement is as follows.
I've 45 records and I want to fetch 10 records each time. It gives successfully up to 40 records. But from 41-45 records, the query returns empty list.
query1 = session
.createQuery(
"FROM mongo c where "
+ "c.ad='555rs5' and "
+ "c.cId='44444sf' and "
+ "c.langId='59ecc8' and c.date < '"
+ tempDate + "' ORDER BY -date")
.setMaxResults(10);
Anything wrong in my query? Please let me know.
Regards
Naresh Veluri
For Hibernate pagination, next to the setMaxResults() method, you also need the setFirstResult() method. Check out this page.
I guess there must be a problem in your loop.
As per the K.C. answer you have not set setFirstResult() I dont know how your query fetching next records.Read Hibernate Doc - setFirstResult().
Query setFirstResult(int firstResult)
Set the first row to retrieve. If not set, rows will be retrieved beginnning from row 0.
Parameters:
firstResult - a row number, numbered from 0
Try below code hope this will help you to solve your problem.
boolean flag = true;
int firstResult = 0;
int pageSize = 10;
int maxResult = 10;
while(flag) {
query1 = session.createQuery("FROM mongo c where "
+ "c.ad='555rs5' and "
+ "c.cId='44444sf' and "
+ "c.langId='59ecc8' and c.date < '"
+ tempDate + "' ORDER BY -date");
query1.setFirstResult(firstResult);
query1.setMaxResults(maxResult);
List<mongo> = query1.list();
//terminate loop if list is empty or records less than pagesize.
if(list.isEmpty() || list.size() < (maxResult-firstResult)) {
flag = false;
} else {
firstResult = firstResult + pageSize;
maxResult = maxResult + pageSize;
}
}

Categories

Resources