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);
Related
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.
I am using temporary tables inside my code in order to [some long sequnce of reasons here] in SQL Server, Java. I was executing my sql queries with using Stament object in java. However, recently I decided to use PreparedStatement in order to avoid injection thing.
My problem is when create a temporary table with using PreparedStatement, I can not reach it with the same prepared statement again. Here is a simple illustration:
sql = "select * into #someTable from (select someColumns from someOtherTable where smth = ? and smth2 = ?)"
PreparedStatement preparedStatement = conn.prepareStatement(sql);
for(int i=0; i<parameters.size(); i++){
preparedStatement.setString(i+1, parameters.get(i).toString());
}
this.rs = preparedStatement.executeQuery();
Until here, it is ok. After getting ResultSet and doing something with it, or without getting a resultSet just for preparedStatement.execute() does not makes difference, I can not reach the #someTable object again.
sql = "select count(*) from #someTable"
preparedStatement = conn.prepareStatement(sql);
this.rs = preparedStatement.executeQuery();
Here this.rs = preparedStatement.executeQuery(); part gives 'Invalid object name #someTable'. I am doing all of the things above with using one Connection object only and without closing or reopening it. I need to use that temp table again. Is there any way to create temp table with PreparedStatement object in java and reuse this temp table again and again? Regards,
Rather late to the party, but facing the same problem and finding the above answer wrong:
Read this article about the problem: https://learn.microsoft.com/en-us/sql/connect/jdbc/using-usefmtonly?view=sql-server-2017
I found that using a PreparedStatement to create the temp table wouldn't work, but if I changed to use a Statement to create the temp table it would work (even without the useFmtOnly).
So start with this (from the MS article) and build on it:
final String sql = "INSERT INTO #Bar VALUES (?)";
try (Connection c = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
try (Statement s = c.createStatement()) {
s.execute("CREATE TABLE #Bar(c1 int)");
}
try (PreparedStatement p1 = c.prepareStatement(sql); PreparedStatement p2 = c.prepareStatement(sql)) {
((SQLServerPreparedStatement) p1).setUseFmtOnly(true);
ParameterMetaData pmd1 = p1.getParameterMetaData();
System.out.println(pmd1.getParameterTypeName(1)); // prints int
ParameterMetaData pmd2 = p2.getParameterMetaData(); // throws exception, Invalid object name '#Bar'
}
}
The temp table you create in the first statement exists for the scope\lifetime of that request. As soon as you call another query, you're in a different scope so it is no longer present as it would have been cleaned up.
Solutions are either make 2 requests in the same call (not great) or create a global temp table that can be accessed by the second query (still not great).
The better solution is to create a stored procedure that does everything you need, with the temp table creation, querying and tidy up encapsulated in the procedure.
PS I can't see any surrounding code, but beware of SQL Injection when building queries in code like this.
Related info:
Scope of temporary tables in SQL Server
It Takes Too Long For Me To Create And Send PreparedStatement's or ResultSet.
How Can I Get MaxID From SQL in Java Method?
Writed this but not working...
private static int getLastId()
{
int returned=0;
try
{
PreparedStatement stat;
ResultSet rs;
String sql="select max(id) from home";
stat=conn.prepareStatement(sql);
rs=stat.executeQuery();
while(rs.next())
{
returned = rs.getInt("id")+1;// just want a new id for new person
}
}
catch (Exception e)
{
System.out.println(""+e);
}
return returned;
}
I Tried To Use It Like This...
//reseting every thing and get lastId+1;
System.out.println("added");
field_name.setText("");
field_pass.setText("");
int temp= getLastId();
field_id.setText(""+temp);
But It Returns 0!
I Don't Have any SQL error.
Did I Use It Wrong?
or ?
Thanks For Help.
You have a few problems here, one of which is that in your current code you aren't actually accessing the max(id) which you put in the query. One way around this is to assign an alias:
PreparedStatement stat;
ResultSet rs;
String sql = "SELECT MAX(id) AS max_id FROM home";
stat = conn.prepareStatement(sql);
rs = stat.executeQuery();
if (rs.next()) {
returned = rs.getInt("max_id") + 1;
}
This fixes the syntax problem, but there is still the problem of whether this is the best way to get the next id. I would recommend that you switch to using an auto increment column, which MySQL will manage for you. Then, you don't need to worry about keeping track of the latest ID value. In fact, you don't even need to specify a value when inserting; the database will handle this for you.
I've looked through this forum and searched the web for a solution to my above problem but could not find something that points me in the right direction. Please forgive me if this is a duplication.
I'm working on a java project where my application interacts with an MS Access 2016 database. One of the functions of my program is to query the db for a specific record and display the data of that record in a gui. Here is my code to retrieve the data:
int i = 0;
String q = "select * from QueryData where id=123456";
try {
pstmnt=conn.prepareStatement(q);
Object obj ;
rs = pstmnt.executeQuery();
while (rs.next()) {
obj=rs.getObject(i+1);
data.add(obj); //where data is a List object i++;
}
} catch ....
Problem is I only get the first value in this record (1st column of record) and there are more data available in the record/row.
Could it be the rs.next() method that is doing this and if so, what should I use to get the next value in this specific record?
ResultSet#next() iterates over the rows in the result set (which, in this case, is just a single row). If you don't know the result set's structure upfront, you can dynamically deduce it from a ResultSetMetaData object:
int i=0;
String q="select * from QueryData where id=123456";
try (PreparedStatement pstmnt = conn.prepareStatement(q);
ResultSet rs = pstmnt.executeQuery()) {
ResultSetMetaData rsmd = rs.getMetaData();
// Assume it's just one row.
// If there's more than one, you need a while loop
if (rs.next()) {
for (int i = 0; i < rsmd.getColumnCount(); ++i) {
data.add(rs.getObject(i + 1));
}
}
}
Good day, all. I am working on a personal project that needs to interact with an ms access 2016 db. My java application gets data from a user and this info is stored in an Object[]. I am trying to insert the elements of my obj array to a table in my db. This is my code:
Connection conn = null;
PreparedStatement pstmnt = null;
String sql = null;
ResultSetMetaData md = null;
Statement stm = null;
ResultSet rs = null;
int i = 0;
String q = "SELECT * from QueryData";
try{
conn = DriverManager.getConnection("jdbc:ucanaccess://filePath");
stm = conn.createStatement();
rs = stm.executeQuery(q);
md = rs.getMetaData();
int count = md.getColumnCount();
String[] colName = new String[count];
for (int n = 1; n <= count; n++)
colName[n-1] = md.getColumnLabel(n);
while ( i <= data.length) {//data being the object array containing the data to be inserted in db
query = "INSERT into QueryData ('"+colName[i]+"') VALUES ('"+data[i]+"')";
//The following code is where I get the exception
pstmnt = conn.prepareStatement(query);
//some more code follows..
On the first pass throught the while loop, colName[i] is "logDate" which is the first field in the table and data[i] is a LocalDate object formatted as 2016-12-23. I know I did not close the while loop above nor did I given the catch clause, but my program does not run past the pstmnt assignment. I keep getting the exception "net.ucanaccess.jdbc.UcanaccessSQLException: UCAExc:::3.0.7 unexpected token: logDate".
Any assistance will be greatly appreciated as I've scoured the web amd this forum but could not find a working solution to my problem.
You are surrounding your column name with quotes, which isn't allowed. You can use square brackets instead (although not really necessary unless you have spaces in the field names, which Access allows).
query = "INSERT into QueryData (["+colName[i]+"]) VALUES ('"+data[i]+"')";
You might also need to use # instead of ' to delimit the date value. Access used to use # for date delimiters, and I'm not sure if more recent versions accept ':
query = "INSERT into QueryData (["+colName[i]+"]) VALUES (#"+data[i]+"#)";