I have a table called "Transactions". It has 5 attributes: Date, Description, Amount, Clientname, Transaction_ID where Transaction_ID is the primary key. In the example Data, the Clientname, "John Smith" has two transactions where he spend 100.10 and 56.56 each. The SQL Query returns the expected result of 156.66 in PHPMyAdmin, but JDBC doesn't seem to recognize it in the ResultSet.
Here is my code:
public void calculate_client_spending() throws SQLException {
ConnectionClass Databaseloader = new ConnectionClass();
Databaseloader.getConnection();
String sql = "SELECT SUM(Amount) AS total FROM Transactions WHERE Clientname = 'John Smith';";
ResultSet rs = Databaseloader.executeSQLRequestCommand(sql);
// rs.next();
// System.out.println(sum);
ResultSetMetaData rsMetaData = rs.getMetaData();
int numberOfColumns = rsMetaData.getColumnCount();
System.out.println(numberOfColumns);
// get the column names; column indexes start from 1
for (int i = 1; i < numberOfColumns + 1; i++) {
String columnName = rsMetaData.getColumnName(i);
// Get the name of the column's table name
if ("total".equals(columnName)) {
System.out.println("Bingo!");
rs.last();
int count = rs.getRow();
rs.beforeFirst();
System.out.println(count);
while (rs.next()) {
Results_trasactions.setText("");
System.out.println("The total profits today are: " + rs.getString(1));
}
}
}
}
This Query returns null in this example, but if I did rs.getDouble(1), it would return 0. Any idea what the issue may be here? I am able to get similar SUM Query's to work, such as a SUM for all clients and the WHERE clause seems to work for my primary key, but this specific Query JDBC doesn't seem to like it even though the SQL is valid in PHPmyadmin which makes me want to believe that it is a Java issue and not a SQL issues. Any help would be greatly appreciated.
Since this is unfortunately way too long for a comment:
Not meaning to be mean, but maybe you shouldn't create a new account to answer your deleted question again (https://stackoverflow.com/questions/59570469) -> Google Cache - also, the Database Classes you're using give away your "real" account (How to retrieve the "total" variable representing a sum in a resultset) - so I'm voting to close this question yet again.
However, to be at least some hints:
ConnectionClass Databaseloader = new ConnectionClass();
Databaseloader.getConnection();
Databaseloader isn't any default JDBC class, but rather some (poorly) written static class, which looks like a weird wrapper to me. You can do it, but by any means you wouldn't do it statically. And by throwing the methods into Google, you find: almost nothing.
For mySQL you'd acquire a database connection like that:
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "sa", "sa")
and rather work with the connection object.
I'd recommend you to do the following:
Read how to connect your database in Java
Read how to create and execute a prepared statement
Read how to extract a result from a result set
Inform yourself about parameter binding (avoid SQL injections)
Profit!
All these topics are well covered on stackoverflow.
Related
I have an assignment where I need to update records using a PreparedStatement. Once the record have been updated as we know update query return count, i.e., number of row affected.
However, instead of the count I want the rows that were affected by update query in response, or at least a list of id values for the rows that were affected.
This my update query.
UPDATE User_Information uInfo SET address = uInfo.contact_number || uInfo.address where uInfo.user_id between ? AND ?;
Normally it will return count of row affected but in my case query should return the ids of row or all the row affected.
I have used the returning function of PostgreSQL it is working but is not useful for me in that case.
i have used returning function of PostgreSQL but is not useful for me
It should be. Perhaps you were just using it wrong. This code works for me:
sql = "UPDATE table1 SET customer = customer || 'X' WHERE customer LIKE 'ba%' RETURNING id";
try (PreparedStatement s = conn.prepareStatement(sql)) {
s.execute(); // perform the UPDATE
try (ResultSet rs = s.getResultSet()) {
// loop through rows from the RETURNING clause
while (rs.next()) {
System.out.println(rs.getInt("id")); // print the "id" value of the updated row
}
}
}
The documentation indicates that we can also use RETURNING * if we want the ResultSet to include the entire updated row.
Update:
As #CraigRinger suggests in his comment, the PostgreSQL JDBC driver does actually support .getGeneratedKeys() for UPDATE statements too, so this code worked for me as well:
sql = "UPDATE table1 SET customer = customer || 'X' WHERE customer LIKE 'ba%'";
try (PreparedStatement s = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
s.execute(); // perform the UPDATE
try (ResultSet rs = s.getGeneratedKeys()) {
while (rs.next()) {
System.out.println(rs.getInt(1)); // print the "id" value of the updated row
}
}
}
Thanks, Craig!
You might be able to use JDBC's support for getting generated keys. See the Connection.prepareStatement(String sql, int[] columnIndexes) API method, then use Statement.getGeneratedKeys() to access the results.
The spec says "the driver will ignore the array if the SQL statement is not an INSERT statement" but I think PostgreSQL's JDBC driver will actually honour your request with other statement types too.
e.g.
PreparedStatement s = conn.prepareStatement(sql, new String[] {'id'})
s.executeUpdate();
ResultSet rs = s.getGeneratedKeys();
Otherwise, use RETURNING, as Gord Thompson describes.
There are two way of doing it
1. by passing an array of column name or index of column prepareStatement
i.e conn.prepareStatement(sql, new String[] {'id','uname'})
and
2. by using Statement.RETURN_GENERATED_KEYS in prepareStatement.
My code is for this i.e as per my requirement i have developed my code you can have a look for better idea.
private static final String UPDATE_USER_QUERY= "UPDATE User_Information uInfo SET address = uInfo.contact_number || uInfo.address where uInfo.user_id between ? AND ?;";
//pst = connection.prepareStatement(UPDATE_USER_QUERY,columnNames);
pst = connection.prepareStatement(UPDATE_USER_QUERY,Statement.RETURN_GENERATED_KEYS);
ResultSet rst = pst.getGeneratedKeys();
List<UserInformation> userInformationList = new ArrayList<UserInformation>();
UserInformation userInformation;
while (rst.next()){
userInformation = new UserInformation();
userInformation.setUserId(rst.getLong("user_id"));
userInformation.setUserName(rst.getString("user_name"));
userInformation.setUserLName(rst.getString("user_lName"));
userInformation.setAddress(rst.getString("address"));
userInformation.setContactNumber(rst.getLong("contact_number"));
userInformationList.add(userInformation);
}
That think i need to achieve in this case.
Hope so this will help you a lot.
i have one problem with database in java
my code is ( its only one small part of my project)
public void Read_from_DB(int exhibition_id){
Statement stmt = null;
Connection connect = null;
try {
connect=MYConnection.new_connection();
stmt = connect.createStatement();
QuestionCatalog.get_QuestionCatalog_instance().setShow_quest(new ArrayList<Question>());
String sql = "SELECT * FROM question WHERE Selection=0 AND exhibition_id="+exhibition_id;
//System.out.println(sql);
ResultSet rs = stmt.executeQuery(sql);
System.out.println("!");
System.out.println("->"+rs.getFetchSize());
while(rs.next()){
Question jd=new Question();
System.out.println("!!!");
jd.setQuestion_id(rs.getInt("Question_id"));
jd.setQuestion(rs.getString("Question"));
jd.setQuestion(rs.getString(exhibition_id));
jd.getOption_2().setContent(rs.getString("Content2"));
QuestionCatalog.get_QuestionCatalog_instance().getShow_quest().add(jd);
System.out.println("size"+QuestionCatalog.get_QuestionCatalog_instance().getShow_quest().size());
MYConnection.close_connection(stmt, connect);
}
}catch (Exception e) {
}
}
when i execute this code it dosent work
my database table name is "question"
but when i change the name in this query to "Question" , don't get any error
then i think it doesn't execute my query,my main is
public static void main(String[] args) {
DB_question d=new DB_question();
d.Read_from_DB(1);
}
and "MYConnection.new_connection();" in part on of code return a connection,( i test it in another class it work)
the result in console is :
SELECT * FROM Question WHERE Selection=0 AND exhibition_id=1
!
->0
it haven't show "!!!"that is result of "System.out.println("!!!");"
then i think it doesnt work :|
thanks
p.s the picture of my db
picture
What I understand from your question is improper output on case sensitive names on table names or column names. Am I right?
As far as I know, reserved words like SELECT, FROM, etc. are case in-sensitive in all OS's. And all other user defined object names are case-sensitive, in *ix OS environment. But not in in Windows OS environment.
But all RDBMS configurations should be allowing case-insensitivity for cross platform deployment. This is the reason why your change from question to Question did not throw an error.
And regarding the outcome of your query:
I fear you have tested your query on different databases or servers. They might not have same data and hence always not entering into while( rs.... loop.
Change your code as below and see what the output is:
ResultSet rs = stmt.executeQuery(sql);
System.out.println("!");
System.out.println("->"+rs.getFetchSize());
rs.beforeFirst();
rs.last();
int rowCount = rs.getRow();
System.out.println( "---> rowCount: " + rowCount );
rs.beforeFirst();
while( ...
Also refer to:
DBMS Identifiers and Case Sensitivity - MysQL
I'm writing data from Java to an Access database on Windows 32 bit. When I write a record, I need to retrieve the row ID / primary key so that I can a) update the record easily if I want to and b) cross reference other data to that record.
When did something similar in C, I could make a updatable cursor which allowed me to write a new record and simultaneously retrieve the row ID. With Java, it looks as though I should be able to do this, but it throws an exception with the following code.
con = openAccessDatabase();
String selectString = "SELECT ID, RunCount FROM SpeedTable";
try {
PreparedStatement selectStatement = con.prepareStatement(selectString,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet idResult = selectStatement.executeQuery();
int id;
for (int i = 0; i < nWrites; i++) {
idResult.moveToInsertRow();
idResult.updateObject(1, null); // this line makes no difference whatsoever !
idResult.updateInt(2, i);
idResult.insertRow(); // throws java.sql.SQLException: [Microsoft][ODBC Microsoft Access Driver]Error in row
id = idResult.getInt(1);
}
selectStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
The only thing I've been able to do is to write a new record and then run a different query to get the Row id back ...
String insertString = "INSERT INTO SpeedTable (RunCount) VALUES (?)";
String idString = "SELECT ID FROM SpeedTable ORDER BY ID DESC";
//
try {
ResultSet idResult = null;
PreparedStatement preparedStatement, idStatement;
preparedStatement = con.prepareStatement(insertString,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
idStatement = con.prepareStatement(idString,
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
for (int i = 0; i < nWrites; i++) {
// write the data into the database
preparedStatement.setInt(1, i);
preparedStatement.execute();
// re-run the query to get the index back from the database.
idResult = idStatement.executeQuery();
idResult.next();
int lastIndex = idResult.getInt(1);
idResult.close();
}
This works but becomes impossibly slow when the table has more than a few 10's of 1000's of records in it. There is also a risk of returning the wrong ID if two parts of the program start writing at the same time (unlikely but not impossible).
I know that at least one suggestion will be to either not use Java or not use Access, but they are not options. It's also part of a free open source software package, so I'm reluctant to pay for anything. Writing my own C JNI interface which provides the basic functionality that I need for my application is even less appealing.
Not sure if this works for MS Access but you can try:
st.executeUpdate("INSERT INTO SpeedTable (RunCount) VALUES (1000)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = st.getGeneratedKeys();
rs.next();
long id = rs.getLong(1);
I am encountering some difficulties trying to, in a dynamic way, create a new table using PreparedStatement. I am trying to add a unknown number of columns and their respective types and sizes. I keep getting SQL Syntax errors, but I suspect this may not be the case here.
Variables used:
con = Connection object
colNames = String[] containing column names ("person", "email" etc)
colTypes = String[] containing column types ("varchar", "int" etc)
colSizes = String[] containing column sizes ("100", "11", etc)
Should be pretty self-explanatory.
con.setAutoCommit(false);
String sql = "? ?(?),";
PreparedStatement ps = con.prepareStatement(sql);
ps.addBatch("create table " + tablename + "( ");
for (int i = 0; i < colNames.length; i++){
if (!(i == colNames.length-1)) {
ps.setString(1, colNames[i]);
ps.setString(2, colTypes[i]);
ps.setString(3, colSizes[i]);
} else {
String format = "%s %s(%s)";
String lastLine = String.format(format, colNames[i], colTypes[i], colSizes[i]);
ps.addBatch(lastLine);
}
}
ps.addBatch(");");
ps.executeBatch();
NOTE: Yes, this is homework. I don't want any dead giveaways, rather pointers as to in what way I am misusing some functions, which I suspect.
Best regards,
Krys
You need to give the full SQL statement to addBatch. It is not a tool to construct a dynamic SQL statement. It is a tool to improve performance when running multiple statements. You don't need it here.
You also don't need a PreparedStatement here, as you are not going to have bind variables (i.e. column data as opposed to column names) and are not going to run the same SQL repeatedly (but it does not hurt, either). setString and friends do not work for column or table names, just for data.
A StringBuilder is a good tool to construct a String with variable parts.
I use the following code
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection("jdbc:odbc:access");
String sql = "Select * from table";
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery( sql );
ResultSetMetaData md = rs.getMetaData();
int columns = md.getColumnCount();
for (int i = 1; i <= columns; i++) {
columnNames.addElement( md.getColumnName(i) );
}
while (rs.next()) {
Vector row = new Vector(columns);
for (int i = 1; i <= columns; i++){
row.addElement( rs.getObject(i) );
}
data.addElement( row );
}
rs.close();
stmt.close();
}catch(Exception e){
System.out.println(e);
}
It displays:
java.sql.SQLException:[Microsoft][ODBC Driver Manager] Invalid descriptor index
How is this caused and how can I solve it?
I have had the same exact error, this out of an ODBC Express Driver for Delphi.
The solution I have found is:
Place your varchar(max) and or varbinary(max) fields at the end of your select Query. (Order in the table definition doesn't matter).
This really fixed it for us, thought to share it with you guys.
I doubt the exception is thrown by one of the lines in the posted code. I have my reasons to state so.
A SQLException with the message "Invalid descriptor index" is usually obtained when you read the result set incorrectly. There are various ways in which this scenario can manifest:
Reading columns out of sequence. I'm afraid, some JDBC drivers will require you to read columns in order, starting at the first column. That's the way some drivers have been written; you cannot skip any columns when reading the resulting result set, as the drivers are actually reading a stream and converting objects in the stream to objects of the JDBC types.
You might be reading a column, whose index is invalid, or whose column name doesn't match any of the returned columns in the result set. The simple resolution is to either fix the query to return the needed column, or fix your code to not read the absent column.
If you need to solve it, you need to know which one of the above conditions is true in your code, and rectify accordingly.
I know this bug for many years by using ODBC driver with PHP. Try to place your text and image columns at the end of select list.Dont use
select * from t
but enumerate rigidly
select plain_column1, plain_column2, .... image_column from t
Unfortunately Microsoft doesn't get tired by fixing the bug. JDBC driver works OK.
That will occur if you're trying to get the resultset variable value in the index value of 0.
For example:
Consider a table which has 5 columns:
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName);
while(rs.next())
{
for(int i=0;i<5;i++)
//This will throw the exception
System.out.println(rs.getString(i)); //Since the value will be returned from 1 not 0
//The below code was the right way
System.out.println(rs.getString(i+1));
}
I got an error
SEVERE: null
java.sql.SQLException: [Microsoft][SQL Server Native Client 10.0]Invalid Descriptor Index
code was
String sqlStr = "select soldItems.payment as aa, Sysuser.name as sname, Books.Name as abookName, soldItems.Qunt as qunt, soldItems.date as soldBooks from Sysuser inner join soldItems on soldItems.CustomerId=Sysuser.id inner join Books on Books.bookId=soldItems.bookId where CustomerId='" + cusId + "' and PaymentDone is NULL";
System.out.println(sqlStr);
DbConnection con = new DbConnection();
con.getConnection();
ResultSet rs = con.getData(sqlStr);
while (rs.next()) {
int i = 0;
dataArry[i][0] = rs.getString("abookName");
dataArry[i][1] = rs.getString("qunt");
dataArry[i][2] = rs.getString("aa");
dataArry[i][3] = rs.getString("soldBooks");
i++;
}
the fix is rs.getString needs to be in the same order of the SQL
so the code needs to be
dataArry[i][2] = rs.getString("aa");
dataArry[i][0] = rs.getString("abookName");
dataArry[i][1] = rs.getString("qunt");
dataArry[i][3] = rs.getString("soldBooks");
I have explained #Remco answer with example which is simple and short and helped me to solve my problem. Find the column info of MYTABLE first and place the column at the end with max values(suppose varchar(max) and or varbinary(max)). Try the example below.
With Error
library(DBI)
library(ODBC)
myquery<- dbGetQuery(con,"SELECT * FROM MYTABLE")
Error in Result_fetch....: Invalid Descriptor Index
Solution
dbcolumnInfo(dbSendWuery(con,"SELECT * FROM MYTABLE")
From the results for DateTimeSampled is varchar(max). Place this column at the end of MYTABLE using following query.
myquery<- dbGetQuery(con,"SELECT [PROCHI],[hb_extract],
[QuantityValue],[QuantityUnit],[Interpretation],
[LabNumber],[LocalClinicalCodeValue],[DateTimeSampled]
FROM MYTABLE")
Enjoy SQL with R