Following is my code(Re-constructed) which select & update STATUS field depending upon the conditions. (Using Servlets, Oracle as Backend and JDBC driver)
ResultSet rs=null;
String query = "select A.NAME, A.ADDRESS, A.STATUS, B.CLASS from TABLE_ONE A, TABLE_TWO B where A.STATUS='N'";
pstmt = con.prepareStatement(query,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
rs = pstmt.executeQuery();
while(rs.next())
{
String name = rs.getString("NAME");
String address = rs.getString("ADDRESS");
String class = rs.getString("CLASS");
String msg = //Other statements to check what status to be set
if(msg.equals("OK"))
rs.updateString("STATUS", "S");
else
rs.updateString("STATUS", "E");
rs.updateRow();
}
I am getting the error while updating:
java.sql.SQLException: Invalid operation for read only resultset: updateString
Any suggestions will be appreciated.
Update 1:
The same code was working when select statement was selecting data from single table, so is there any issue when selecting data from two tables in single query?
[Note: As #javaBeginner has mentioned in comments it will work only for one table.]
The following limitations are placed on queries for enhanced result sets. Failure to follow these guidelines will result in the JDBC driver choosing an alternative result set type or concurrency type.
To produce an updatable result set (from specification):
A query can select from only a single table and cannot contain any join operations.
In addition, for inserts to be feasible, the query must select all non-nullable columns and all columns that do not have a default value.
* A query cannot use "SELECT * ". (But see the workaround below.)
* A query must select table columns only. It cannot select derived columns or aggregates such as the SUM or MAX of a set of columns.
To produce a scroll-sensitive result set:
A query cannot use "SELECT * ". (But see the workaround below.)
A query can select from only a single table.
Try This :
Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
//Execute a query
String sql = "select A.NAME, A.ADDRESS, A.STATUS, B.CLASS from TABLE_ONE A, TABLE_TWO B where A.STATUS='N'";
ResultSet rs = stmt.executeQuery(sql);
//Extract data from result set
rs.beforeFirst();
while(rs.next())
{
String name = rs.getString("NAME");
String address = rs.getString("ADDRESS");
String class = rs.getString("CLASS");
String msg = //Other statements to check what status to be set
if(msg.equals("OK"))
rs.updateString("STATUS", "S");
else
rs.updateString("STATUS", "E");
rs.updateRow();
}
Just changed Prepared statement to create statement
SELECT * makes the resultSet readonly. SELECT COLUMN_NAME makes it updatable.
So instead of SELECT * FROM TABLE use SELECT COLUMN1, COLUMN2, ... FROM TABLE.
Related
I have connected Java to SSMS and can call data from the server no problems using something like this:
String cell = "SELECT [Close] FROM ExcelData WHERE id_num = 3";
Statement st4 = con.createStatement();
ResultSet rs4 = st4.executeQuery(cell);
while (rs4.next())
{
Float close = rs4.getFloat("close");
System.out.format("%s\n", close);
}
When I replace the "SELECT [Close] FROM ExcelData WHERE id_num = 3" to "SELECT #SMA" I get the much questioned "Must declare the scalar variable #SMA.
I do not know how to do that.
Answering my own question to help others who may need to know this...
It cannot be done. The work around is to create a table in SQL and insert the variable into the table.
DROP TABLE IF EXISTS SMA
CREATE TABLE SMA (
SMA_Price DECIMAL (6,5),
)
INSERT INTO SMA VALUES (#SMA);
SELECT * FROM SMA;
You can then call "SELECT * FROM SMA" from Java.
I have some data in an SQLite Database. The following queries in SQLiteBrowser give me exactly the ResultSet I want:
With TempTable0 AS (SELECT Source, Date, Value AS Close FROM FinData WHERE Type = 'Close'),
TempTable1 AS (SELECT Source, Date, Value AS Colume FROM FinData WHERE Type = ' Colume')
SELECT DISTINCT TempTable0.Date, Close, Colume FROM TempTable0
JOIN TempTable1 ON TempTable1.Date = TempTable0.Date
Now, I tried to get this working as a single query via a simple executeQuery-Method from Java and read the data in a Matrixlike-DataStructure:
String sql = "With TempTable0 AS (SELECT Source, Date, Value AS Close FROM FinData WHERE Type = 'Close'), TempTable1 AS (SELECT Source, Date, Value AS Colume FROM FinData WHERE Type = ' Colume') SELECT DISTINCT TempTable0.Date, Close, Colume FROM TempTable0 JOIN TempTable1 ON TempTable1.Date = TempTable0.Date";
Connection Conn = DriverManager.getConnection(SQLCommunication.urlDB);
Statement stmt = Conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next() ) {
String res = rs.getString("Close");
DataMatrix.get("Close").add(res);
res = rs.getString("Colume");
DataMatrix.get("Colume").add(res);
}
However, the Resultset returns null.
I suspect this is because, it cannot work with two dependent SQLite-Queries, however, I have no idea, how to solve this.
I am no expert on SQLite and Java interaction and I am really running out of ideas, right now. Do you have any sugestions? (Even maybe a tip on nesting these two statements in one so it can be executed in one shot?)
Thanks so much!
Wiwi
In PostgreSQL user is a reserved keyword that is used in an internal table, however I also have a separate user table in my own database that I need to use. Whenever I try to execute INSERT or UPDATE statements on the table, it generates the following error: The column name 'id' was not found in this ResultSet.
This is the Java code I am currently using:
PreparedStatement stat1 = conn.prepareStatement("SELECT id FROM user;");
PreparedStatement stat2 = conn.prepareStatement("UPDATE user SET date_created = ? , last_updated = ? , uuid = ? WHERE id = ?;");
ResultSet rs = stat1.executeQuery();
while(rs.next()){
UUID uuid = UUID.randomUUID();
String tempId = uuid.toString();
stat2.setTimestamp(1, curDate);
stat2.setTimestamp(2, curDate);
stat2.setString(3, tempId);
stat2.setLong(4,rs.getLong("id"));
stat2.executeUpdate();
}
So my question is, how could I insert or update the values in my personal user table without interfering with the keyword restriction?
Use this:
prepareStatement("UPDATE \"user\" set date_created = ?")
Or, better yet, rename your user table to something else, like users:
ALTER TABLE "user" RENAME TO users;
Escape the table name like this
select * from "user";
I have this piece of code, with a prepared statement. I know the query is redundant. the parameter id is a string <space>413530 (" 413530"). Please note the preceding whitespace character.
String query = "SELECT RSCode as id FROM Customer WHERE RSCode=?";
PreparedStatement newPrepStatement = connection
.prepareStatement(query);
newPrepStatement.setString(1, id);
resultSet1 = newPrepStatement.executeQuery();
while (resultSet1.next()) {
System.out.println("Got a result set.");
logindata.add(resultSet1.getString("id"));
}
I do not get any results after executing this query.
Now, if I use the same statements and append the parameter as part of the string as follows:
String query = "SELECT RSCode as id FROM Customer WHERE RSCode=" + id;
PreparedStatement newPrepStatement = connection
.prepareStatement(query);
resultSet1 = newPrepStatement.executeQuery();
while (resultSet1.next()) {
System.out.println("Got a result set.");
logindata.add(resultSet1.getString("id"));
}
I get a result as after executing this prepared statement. Same also works with a java.sql.statement
I wish to know why the driver ignores the whitespace in the second piece of code, but has a problem in the first part.
If you use setString the parameter will be bound as a string resulting in this SQL (considering the bound parameter an SQL string):
SELECT RSCode as id FROM Customer WHERE RSCode=' 0123';
If you use concatenation the SQL used will be (considering the concatenated value as an integer, since space will be ignored as part of the SQL syntax):
SELECT RSCode as id FROM Customer WHERE RSCode=<space>0123;
In this case I would advise to convert it to int or long or whatever it is and bind it with the right type. With setInt() or setLong().
And if you field is a string you could normalize it first using for example:
String normalizedValue = String.trim(value);
newPrepStatement.setString(1, normalizedValue);
or even direct in SQL like:
SELECT RSCode as id FROM Customer WHERE RSCode=TRIM(?);
In scenario - 1, the query will look like this
"SELECT RSCode as id FROM Customer WHERE RSCode=' 413530'"
In scenario - 2, the query will look like this
"SELECT RSCode as id FROM Customer WHERE RSCode= 413530"
I am having some problems and I'm sure it's something stupid.
So I have a query like
SELECT name, id, xyz FROM table ORDER BY ?
then later down the road setting the ? doing a
ps.setString(1, "xyz");
I am outputting the query and the value of xyz in the console. When I loop through the ResultSet returned from the PreparedStatement the values are not in the correct order. They are in the returned order as if I had left the ORDER BY clause off. When I copy/paste the query and the value into TOAD it runs and comes back correctly.
Any ideas to why the ResultSet is not coming back in the correct order?
The database will see the query as
SELECT name, id, xyz FROM table ORDER BY 'xyz'
That is to say, order by a constant expression (the string 'xyz' in this case). Any order will satisfy that.
? is for parameters, you can't use it to insert column names. The generated statements will look something like
SELECT name, id, xyz FROM table ORDER BY 'xyz'
so that your entries are sorted by the string 'xyz', not by the content of column xyz.
Why not run:
ps.setInteger(1, 3);
Regards.
EDIT: AFAIK Oracle 10g supports it.
PreparedStatement placeholders are not intend for tablenames nor columnnames. They are only intented for actual column values.
You can however use String#format() for this, that's also the way I often do. For example:
private static final String SQL_SELECT_ORDER = "SELECT name, id, xyz FROM table ORDER BY %s";
...
public List<Data> list(boolean ascending) {
String order = ascending ? "ASC" : "DESC";
String sql = String.format(SQL_SELECT_ORDER, order);
...
Another example:
private static final String SQL_SELECT_IN = "SELECT name, id, xyz FROM table WHERE id IN (%s)";
...
public List<Data> list(Set<Long> ids) {
String placeHolders = generatePlaceHolders(ids.size()); // Should return "?,?,?..."
String sql = String.format(SQL_SELECT_IN, placeHolders);
...
DAOUtil.setValues(preparedStatement, ids.toArray());
...
The database will see the query like this
SELECT name, id, xyz FROM table ORDER BY 'xyz'
I think you should add more variable like order_field and order_direction
I assume you have a method like below and I give you an example to solve it
pulbic List<Object> getAllTableWithOrder(String order_field, String order_direction) {
String sql = "select * from table order by ? ?";
//add connection here
PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql);
ps.setString(1,order_field);
ps.setString(2,order_direction);
logger.info(String.valueOf(ps)); //returns something like: com.mysql.jdbc.JDBC4PreparedStatement#a0ff86: select * from table order by 'id' 'desc'
String sqlb = String.valueOf(ps);
String sqlc = sqlb.replace("'"+order_field+"'", order_field);
String sqld = sqlc.replace("'"+order_direction+"'", order_direction);
String[] normQuery = sqld.split(":");
ResultSet result = conn.createStatement().executeQuery(normQuery[1]);
while(result.next()) {
//iteration
}
}