Batch Execute as Aysnc Does not update any row - java

I am trying to use aync update of dsc cassandra 3,
Integer count = 0;
String query = "select status, guid from catalog_new where affiliate_id = ? AND store_id =?";
String approveStoreQuery = "UPDATE catalog_new SET status = ? WHERE affiliate_id = ? AND store_id = ? AND guid = ?";
PreparedStatement selectStmt = session.prepare(query);
BoundStatement selectBoundStatement = new BoundStatement(selectStmt);
ResultSet selectSet = session.execute(selectBoundStatement.bind(new Object[]{affiliateId, storeId}));
BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED);
Iterator<Row> rowItr = selectSet.iterator();
while (!selectSet.isFullyFetched()) {
selectSet.fetchMoreResults();
Row row = rowItr.next();
if(row.getInt("status") == statusFrom){
String guid = row.getString("guid");
PreparedStatement preparedStatement = session.prepare(approveStoreQuery);
BoundStatement boundStatement = new BoundStatement(preparedStatement);
batchStatement.add(boundStatement.bind(new Object[]{statusTo, affiliateId, storeId, guid}));
count++;
}
}
session.executeAsync(batchStatement);
return count;
{Here statusFrom is -2 and statusto is -2 , ids are 3 and 9}
This does not update any row, what I am doing wrong here?

I found it:
Just replace the while construct with a do while and you will be fine!
I also tested this code against select fetch statement that has multiple pages, so it should work as expected for you:
import com.datastax.driver.core.*;
import java.util.Iterator;
public class Hello {
public static void main(String[] args) {
Cluster cluster = Cluster.builder()
.addContactPoint("127.0.0.2")
.build();
//I tried to reverse engineer this from your code:
//I think it's relatively close to what you got
/*
CREATE TABLE catalog_new (
affiliate_id text,
store_id text,
guid text,
status int,
PRIMARY KEY(affiliate_id, store_id, guid)
);
-- Just some test data
INSERT INTO catalog_new(affiliate_id, store_id, guid, status) VALUES ('af1', 'st1', 'guid1', 0);
INSERT INTO catalog_new(affiliate_id, store_id, guid, status) VALUES ('af1', 'st1', 'guid2', 0);
INSERT INTO catalog_new(affiliate_id, store_id, guid, status) VALUES ('af1', 'st1', 'guid3', 0);
*/
Session session = cluster.connect();
String affiliateId = "af1";
String storeId = "st1";
Integer statusFrom = 0;
Integer statusTo = 1;
Integer count = 0;
String query = "select status, guid from test.catalog_new where affiliate_id = ? AND store_id =?";
String approveStoreQuery = "UPDATE test.catalog_new SET status = ? WHERE affiliate_id = ? AND store_id = ? AND guid = ?";
PreparedStatement selectStmt = session.prepare(query);
BoundStatement selectBoundStatement = new BoundStatement(selectStmt);
ResultSet selectSet = session.execute(selectBoundStatement.bind(new Object[]{affiliateId, storeId}));
Iterator<Row> rowItr = selectSet.iterator();
BatchStatement batchStatement = new BatchStatement(BatchStatement.Type.UNLOGGED);
// the way you wrote it is
// while (!selectSet.isFullyFetched()) {
// basically you never even go into a loop
// you might try a do while! - that's all there is to it
do {
selectSet.fetchMoreResults();
Row row = rowItr.next();
if (row.getInt("status") == statusFrom) {
String guid = row.getString("guid");
PreparedStatement preparedStatement = session.prepare(approveStoreQuery);
BoundStatement boundStatement = new BoundStatement(preparedStatement);
batchStatement.add(boundStatement.bind(statusTo, affiliateId, storeId, guid));
count++;
}
} while (!selectSet.isFullyFetched());
session.executeAsync(batchStatement);
// I just made simple print without returning anything just to make sure this works, I tried your example locally and everything runs fine
System.out.println(count);
}
}

Related

`createSQLException` when trying to get all rows in MySQL table

I have a simple table consisting of 4 strings and 2 integers (of which one is an ID).
I use a special function to get all rows inside that table:
public Booking[] displayAllBookings() throws ClassNotFoundException, SQLException{
Connection con = connect.getConnection();
PreparedStatement counter = (PreparedStatement) con.prepareStatement("select count(*) from bookings");
ResultSet count = counter.executeQuery();
Booking[] array = new Booking[count.getInt(1)];
String name = null,surname = null,begindate = null,enddate = null;
int persons = 0,i=0;
PreparedStatement posted = (PreparedStatement) con.prepareStatement("SELECT * FROM bookings");
result = posted.executeQuery();
while (result.next()){
begindate = result.getString("begindate");
enddate = result.getString("enddate");
name = result.getString("Name");
surname = result.getString("Surname");
persons = result.getInt("persons");
Booking temp = new Booking(begindate,enddate,name,surname,persons);
array[i++]=temp;
}
return array;
}
But when I execute it I get this exception:
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:897)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:886)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
at com.mysql.jdbc.ResultSetImpl.checkRowPos(ResultSetImpl.java:790)
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2472)
at DataBase.DataCommunicatorBooking.displayAllBookings(DataCommunicatorBooking.java:59)
at DataBase.main.displayAll(main.java:125)
at DataBase.main.main(main.java:71)
I've tried looking up this exception but I can't find anything that corresponds to my problem.
You are trying to get the value of the column maxPersons which is not even defined in the table... you meant for sure persons
name = result.getString("Name");
maxPersons = result.getInt("persons");
Room temp = new Room(name,maxPersons);
The problem was with the
PreparedStatement counter = (PreparedStatement) con.prepareStatement("select count(*) from bookings");
ResultSet count = counter.executeQuery();
so I used an ArrayList like so:
public Booking[] displayAllBookings() throws ClassNotFoundException, SQLException{
Connection con = connect.getConnection();
ArrayList<Booking> bookings = new ArrayList<Booking>();
String name = null,surname = null,begindate = null,enddate = null;
int persons = 0,i=0;
PreparedStatement posted = (PreparedStatement) con.prepareStatement("SELECT * FROM bookings");
result = posted.executeQuery();
while (result.next()){
begindate = result.getString("begindate");
enddate = result.getString("enddate");
name = result.getString("Name");
surname = result.getString("Surname");
persons = result.getInt("persons");
Booking temp = new Booking(begindate,enddate,name,surname,persons);
bookings.add(temp);
}
return bookings.toArray(new Booking[bookings.size()]);
}
and that solved the problem;
This is because the column "maxPersons" does not exist, you probably ment "persons"

Inserting Data into Sql Using Java Netbeans

I want to insert input given by user into Sql Table using Java, but dont know how many coloumn is need.
eg.
insert into table_name values('"+id+"','"+name+"')
this query is not going to work because I don't know the column name i.e ID, name.
I want the query that is universal for any inserting data.
As per my need I tried this code. I HOPE IT WORKED FOR ALL.
void getTableInput(String tname, String dname) throws ClassNotFoundException, SQLException {
this.tname = tname;
this.dname = dname;
Scanner s = new Scanner(System.in);
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
String conURL = "jdbc:sqlserver://localhost:1433;databaseName=" + this.dname + ";user=JT_DATA;password=1234";
Connection con = DriverManager.getConnection(conURL);
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM " + this.tname);
ResultSetMetaData rsmd = rs.getMetaData();
int colNo = rsmd.getColumnCount();
String colName[] = new String[colNo];
String[] get_User_Input = new String[100];
for (int i = 1; i <=colNo; i++)
{
colName[i-1] = rsmd.getColumnLabel(i);
System.out.print(Arrays.toString(colName) + " : ");
get_User_Input[i-1] = s.next();
}
String store="";
for(int i=0;i<colNo;i++)
{
store += "'"+get_User_Input[i]+"',";
}
store = store.substring(0,store.length() -1);
PreparedStatement pst = con.prepareStatement("insert into "+this.tname+" values ("+ store +")");
pst.executeUpdate();
System.out.println("Data Inserted");
}
But the problem with this is that. This can only insert String Datatype.
I dont think there is any universal query.
If you dont know column name than you can find name of the column by using meta data.
You can get meta data of the connections (database)
DatabaseMetaData databaseMetaData = connection.getMetaData();
You can also get list of the tables.
String catalog = null;
String schemaPattern = null;
String tableNamePattern = null;
String[] types = null;
ResultSet result = databaseMetaData.getTables(
catalog, schemaPattern, tableNamePattern, types );
while(result.next()) {
String tableName = result.getString(3);
}
Listing column name in table.
String catalog = null;
String schemaPattern = null;
String tableNamePattern = "my_table";
String columnNamePattern = null;
ResultSet result = databaseMetaData.getColumns(
catalog, schemaPattern, tableNamePattern, columnNamePattern);
while(result.next()){
String columnName = result.getString(4);
int columnType = result.getInt(5);
}
In this way you can find column name and can create query dynamically.

Fetch primary key generated by sequence using jdbctemplate / jdbc

The situation is as follows:
I have one table(GUI_FILTER) and one sequence(GUI_FILTER_SEQ)
I am inserting data using springjdbctemplate, also can use core jdbc as well.
In the insert query I am retrieving sequence.nextval and also using a keyholder to fetch that back to java as below.
I have tried several ways like using
returnRowCount = namedJdbctmplt.update(sql.toString(), namedParameters, keyHolder, keyColumnNames);
returnRowCount = jdbctemplate.update(psc, keyHolder);
both are failing,
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar []; nested exception is java.sql.SQLSyntaxErrorException: ORA-00936: missing expression
StringBuilder sql = new StringBuilder();
sql.append(" Insert Into MAPS_AMPS.AMPS_GUI_FILTER ");
sql.append(" (FILTER_PRESET_ID,USER_ID,FILTER_PAGE_TXT,FILTER_DISPLY_NM,FILTER_DATA_TXT,ROW_CREATE_TMS,LAST_UPDT_TMS ) ");
sql.append(" values(Select MAPS_AMPS.AMPS_GUI_FILTER_SEQ.NEXTVAL,?,?,?,?,CURRENT_TIMESTAMP ,null from dual) ");
final String sqlQuery = sql.toString();
If I remove the sequence generation part Select MAPS_AMPS.AMPS_GUI_FILTER_SEQ.NEXTVAL to something constant like 30 or so it is working fine.
Is there any way to get sequence value as insert command and also at the same time fetch the primary key using jdbc ?
Complete code is as below.
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = DataAccessException.class)
public Long addFilterPreset(final String userId, final String filterPageCd,
final String filterPresetDisplayName,
final String serializedTaskBrowserSearchObj) {
logger.debug("Start of FilterPresetDaoImpl - addFilterPreset() method");
if(!countSavedFilterPresets(userId,filterPageCd))
return null;
//StringBuilder sql = new StringBuilder();
Map<String, Object> parameterMap = new HashMap<String, Object>();
//sql.append(" Insert Into MAPS_AMPS.AMPS_GUI_FILTER ");
//sql.append(" (FILTER_PRESET_ID,USER_ID,FILTER_PAGE_TXT,FILTER_DISPLY_NM,FILTER_DATA_TXT,ROW_CREATE_TMS,LAST_UPDT_TMS ) ");
//sql.append( "Values( Select MAPS_AMPS.AMPS_GUI_FILTER_SEQ.NEXTVAL,:userId,:filterPageCd,:filterPresetDisplayName,:filterPresetData,CURRENT_TIMESTAMP ,null)" );
/*parameterMap.put("userId", userId);
parameterMap.put("filterPageCd", filterPageCd);
parameterMap.put("filterPresetDisplayName", filterPresetDisplayName);
parameterMap.put("filterPresetData", serializedTaskBrowserSearchObj);
*/
StringBuilder sql = new StringBuilder();
sql.append(" Insert Into MAPS_AMPS.AMPS_GUI_FILTER ");
sql.append(" (FILTER_PRESET_ID,USER_ID,FILTER_PAGE_TXT,FILTER_DISPLY_NM,FILTER_DATA_TXT,ROW_CREATE_TMS,LAST_UPDT_TMS ) ");
sql.append(" values(Select MAPS_AMPS.AMPS_GUI_FILTER_SEQ.NEXTVAL,?,?,?,?,CURRENT_TIMESTAMP ,null from dual) ");
final String sqlQuery = sql.toString();
logger.info("SQL Add Filter Preset Query : {}", sqlQuery);
int returnRowCount = 0;
KeyHolder keyHolder = new GeneratedKeyHolder();
final String[] keyColumnNames = {"FILTER_PRESET_ID"};
SqlParameterSource namedParameters = new MapSqlParameterSource(parameterMap);
PreparedStatementCreator psc = new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection connection)
throws SQLException {
PreparedStatement ps = connection.prepareStatement(sqlQuery, keyColumnNames);
ps.setString(1, userId);
ps.setString(2, filterPageCd);
ps.setString(3, filterPresetDisplayName);
ps.setString(4, serializedTaskBrowserSearchObj);
return ps;
}
};
try{
long startValue = System.currentTimeMillis();
//returnRowCount = namedJdbctmplt.update(sql.toString(), namedParameters, keyHolder, keyColumnNames);
returnRowCount = jdbctemplate.update(psc, keyHolder);
long endValue = System.currentTimeMillis();
logger.info("Filter Preset added in {} seconds", (endValue - startValue)/1000);
}catch(Exception e){
logger.info("Exception while adding filter preset - " + "userId : "+userId+" filterPageCd : "+filterPageCd +" filterPresetData : "+serializedTaskBrowserSearchObj);
}finally{
logger.debug("End of FilterPresetDaoImpl - addFilterPreset() method");
}
if (returnRowCount > 0)
return keyHolder.getKey().longValue();
return null;
}
Error
You don't need the VALUES keyword when inserting a result from query.
StringBuilder sql = new StringBuilder();
sql.append(" Insert Into MAPS_AMPS.AMPS_GUI_FILTER ");
sql.append(" (FILTER_PRESET_ID,USER_ID,FILTER_PAGE_TXT,FILTER_DISPLY_NM,FILTER_DATA_TXT,ROW_CREATE_TMS,LAST_UPDT_TMS ) ");
sql.append(" (Select MAPS_AMPS.AMPS_GUI_FILTER_SEQ.NEXTVAL,?,?,?,?,CURRENT_TIMESTAMP ,null from dual) ");
final String sqlQuery = sql.toString();
To get an inserted value try using RETURNING clause: some details are discussed in this post Oracle's RETURNING INTO usage in Java (JDBC, Prepared Statement)
However, you can use RETURNING clause for INSERT only if you use the VALUES keyword, so you can't have both. As it's discussed here: PLSQL Insert into with subquery and returning clause (Oracle)

Find tables in oracle that dont have composite primary key using DatabaseMetaData Java

String [] tableTypes = { "TABLE" };
DatabaseMetaData md = (DatabaseMetaData) dbConnection.getMetaData();
ResultSet rs = md.getTables(null, null, "%", tableTypes);
while (rs.next()) {
System.out.println(rs.getString(3));
}
Im using this part of the code to get all tables from my local oracle database but I need to change it in order to get back only the tablet that have only one primary key. Any ideas?
You could use DatabaseMetaData.getPrimaryKeys() for each table in that loop:
String [] tableTypes = { "TABLE" };
DatabaseMetaData md = dbConnection.getMetaData(); // the cast is unnecessary!
ResultSet rs = md.getTables(null, null, "%", tableTypes);
while (rs.next())
{
String schema = rs.getString(2);
String table = rs.getString(3);
ResultSet pkRs = md.getPrimaryKeys(null, schema, table);
int colCount = 0;
while (pkRs.next())
{
colCount ++;
}
pkRs.close();
if (colCount = 1)
{
System.out.println("Table " + table + " has a single column primary key");
}
}
However, this will be awfully slow. Using a query that retrieves this information directly from user_constraints and user_cons_columns is going to be a lot faster:
select col.table_name, count(*)
from user_constraints uc
join user_cons_columns col
on col.table_name = uc.table_name
and col.constraint_name = uc.constraint_name
where constraint_type = 'P'
group by col.table_name
having count(*) = 1;
You can use this code :
static Statement statement = null;
static ResultSet result = null;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
try {
Class.forName(driverClassName);
dbConnection = DriverManager.getConnection(url, username, passwd);
statement = dbConnection.createStatement();
String[] tableTypes = {"TABLE"};
DatabaseMetaData dbmd;
dbmd = dbConnection.getMetaData();
result = dbmd.getTables("%", username, "%", new String[]{tableTypes[0]});
while (result.next()) {
String tableName = result.getString("TABLE_NAME");
ResultSet tempSet = dbmd.getPrimaryKeys(null, username, tableName);
String keyName="";
int counter=0;
while (tempSet.next()) {
keyName = tempSet.getString("COLUMN_NAME");
counter++;
}
if(counter == 1) {
System.out.println(tableName);
}
}
} catch (Exception e) {
}
}
Table can have up to one primary key. This primary can be compound - i.e. consisting of multiple columns. The other (2nd) key might be UNIQUE (+ not NULL) which is not exactly the same as primary.
Best way how to check columns is to query ALL_CONTRAINTS view. JDBC method DatabaseMetaData has only limited functionality.

Mysql select and update column in one query

Is possible to merge my following queries into one? I'm using mysql as my database.
String qry = "SELECT id FROM customers WHERE completed=false AND server=?";
ps = connection.prepareStatement(qry);
ps.setString(1,getServerId());
rs = ps.executeQuery();
final Set<Long> ids = new HashSet<>();
while (rs.next()) {
ids.add(rs.getLong(1));
}
qry = "";
for (long l : ids) {
qry += "UPDATE customers SET completed=true WHERE id = "+l+"; ";
}
... execute query, close streams, and do some application logic with ids from database...
You can just
UPDATE customers SET completed=true WHERE completed=false AND server=?
Edit: You provided the information saying you need to actually use the Ids.
Select normally then build a string in the format MySql understands as a "list", it will certainly be faster than multiple update queries and will cost less bytes to send over the network. Here is the snippet:
String qry = "SELECT id FROM customers WHERE completed=false AND server=?";
ps = connection.prepareStatement(qry);
ps.setString(1,getServerId());
rs = ps.executeQuery();
final Set<Long> ids = new HashSet<>();
while (rs.next()) {
ids.add(rs.getLong(1));
}
qry = "";
if(ids.size()>0) {
StringBuilder idsAsString = new StringBuilder();
for(int i = 0; i < ids.size(); i++) {
idsAsString.append(ids.get(i));
if(i < ids.size()-1)
idsAsString.append(",");
}
qry = "UPDATE customers SET completed=true WHERE id IN ("+idsAsString+"); ";
}
instead of building multiple UPDATE statements in a for loop.

Categories