Upon converting from ODBC and MS Access Driver, I now cannot copy a table from a source database with the following SQL:
INSERT INTO TestInfo SELECT * FROM [ C:\Data\P81\LCAP.MDB ].[TestInfo]
The result is an exception: "invalid schema name: C__DATA_P81_LCAP_MDB"
How can I do this in UCanAccess/hsqldb?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If you aren't accessing to a second database you have just to establish another connection.
Also, if you want to use the same connection, you have to import the TestInfo table in the first database as linked table.
If it's the same database of your connection, you shouldn't use the schema name.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I didn't give you the full story. I have created a new database by copying a default with some constant tables and some empty tables to be filled in. Then I connect to the new db and begin to copy from an old (source) database into the new one to which I have established a connection in PocDatabase.connection. Below is one of the copy methods.
//copytablefromasourcedbintocurrentdbpublicstaticvoidcopy(){Stringsource=PocDatabase.sourceDbfile;//attempttocopywholetableSystem.out.println("TestInfoDbTable.copy: from: "+source);try(Statementstatement=PocDatabase.connection.createStatement();){Stringquery="INSERT INTO TestInfo "+"SELECT * FROM ["+source+"].[TestInfo]";statement.execute(query);}catch(SQLExceptionex1){System.err.println("TestInfoDbTable.copy: Exception: "+ex1);}}
So, the variable source contains the location of the source database from which I want to copy the TestInfo table into the currently connected database.
I don't understand your statement "import the TestInfo table in the first database as linked table". What is a linked table?
Thanks for your patience and help.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
A linked table is a "virtual table" in an Access database file that points to a real table in another database file. For example, you can have a table named "TableA" in A.accdb, and you can create a linked table in B.accdb that points to that same table. Then in B.accdb you can refer to the linked table just like it was native to that file, but the information is actually retrieved from (and updates written to) the "real" table in A.accdb.
For more information, see the Microsoft Support article here.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Back on this subject, I need to be able to copy a complete table from another database. (A link will not do.) Is there an SQL statement that can do that, like the example I posted above? Or do I have to read from the source into a result set and then update the target database column by column and row by row (tedious)? Is there a document or website that defines the SQL standard used by this tool?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
UCanaccess can't see database paths as schema whilst Access does it.
You can either follow the tedious approach above or an exciting mixed approach:
-get the ResultSet from the first database through UCanAccess
-get a jackcess connection to second database Database db = DatabaseBuilder.open(new File("my.mdb"));
-use the com.healthmarketscience.jackcess.ImportUtil method public static String importResultSet(ResultSet source,
Database db,
String name,
ImportFilter filter,
boolean useExistingTable)
throws SQLException,
IOException
-Please, let me know your findings: never tried.
Last edit: Marco Amadei 2015-03-24
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Marco. FWIW, I just tried the following code to copy a simple table
ID - Long Integer
TextField
DateField
MemoField
YesNoField
and it seems to have worked fine.
packageucanCopyTable;importjava.io.*;importjava.sql.*;importcom.healthmarketscience.jackcess.*;importcom.healthmarketscience.jackcess.util.ImportUtil;publicclassUCanCopyTable{publicstaticvoidmain(String[]args){// test dataStringsourcePath="C:/Users/Public/test/sourceDb.accdb";StringdestinationPath="C:/Users/Public/test/destinationDb.accdb";StringtableName="Table1";try(Connectionconn=DriverManager.getConnection("jdbc:ucanaccess://"+sourcePath)){try(Statements=conn.createStatement()){try(ResultSetrs=s.executeQuery("SELECT * FROM ["+tableName+"]")){// Jackcess calls:Databasedb=DatabaseBuilder.open(newFile(destinationPath));ImportUtil.importResultSet(rs,db,tableName);// create new table}}}catch(Exceptione){e.printStackTrace(System.err);}}}
Last edit: Gord Thompson 2015-03-24
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok, thank you!
For UcanAccess 3, I'm thinking if it may be possible to expose the access file in the same folder as schemas, as well as Access.
This would allow cross-database queries.
Last edit: Marco Amadei 2015-03-24
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It looks like you're running in autocommit mode.
The use of a transaction instead,
connection.setAutocommit(false) before the loop
and
connection.commit() after the loop,
will drammatically improve the performance.
Should you face with memory issues (out of memory), just call connection.commit() each 5000/10000 records.
Please, let me know your results. Just a diamond is forever.
Last edit: Marco Amadei 2015-04-01
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Well, we can still improve drammatically.
Don't you use a scrollable ResultSet but a batch. I hope that's funny for you(SEE THE FINAL NOTE!!!!):
try (
PreparedStatementstmtout=PocDatabase.connection.prepareStatement("insert into ACNav values(?,?,?,?,?,?,?,?,?,?)"); Statementstmtin=PocDatabase.sourceConnection.createStatement();ResultSetrs=stmtin.executeQuery(query);)
{
while(rs.next()){
stmtout.setInt(1,1); // AutoIDstmtout.setTimestamp(2,rs.getTimestamp(2));stmtout.setDouble(3,rs.getDouble(3));stmtout.setDouble(4,rs.getDouble(4));stmtout.setFloat(5,rs.getFloat(5));stmtout.setFloat(6,rs.getFloat(6));stmtout.setFloat(7,rs.getFloat(7));stmtout.setFloat(8,rs.getFloat(8));stmtout.setFloat(9,rs.getFloat(9));stmtout.setFloat(10,rs.getFloat(10));stmtout.addBatch();}
THE FINAL NOTE: JUST BEFORE EACH COMMIT: stmtout.executeBatch();
PS: So doing you can also commit each 20000 rows.
It should take about 20s.
Please, let me know your results.
Last edit: Marco Amadei 2015-04-02
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I did a couple of quick tests with a 5-column table containing 10,000 rows. I found that if I created the table structure in the destination database first, then the following code took about 1,600 ms to run:
connStr="jdbc:ucanaccess://C:/Users/Public/UCanAccessDemo.accdb";try(Connectionconn=DriverManager.getConnection(connStr)){StopWatchsw=newStopWatch();sw.start();try(Connectionconn2=DriverManager.getConnection("jdbc:ucanaccess://C:/Users/Gord/Desktop/target.accdb")){conn2.setAutoCommit(false);try(PreparedStatementps=conn2.prepareStatement("INSERT INTO TestData10k (ID, TextField, LongIntegerField, DoubleField, Tasked) VALUES (?,?,?,?,?)")){try(Statements=conn.createStatement()){try(ResultSetrs=s.executeQuery("SELECT * FROM TestData10k")){while(rs.next()){ps.setInt(1,rs.getInt(1));ps.setString(2,rs.getString(2));ps.setInt(3,rs.getInt(3));ps.setDouble(4,rs.getDouble(4));ps.setBoolean(5,rs.getBoolean(5));ps.addBatch();}ps.executeBatch();conn2.commit();}}}}sw.stop();System.out.println(sw.getTime());}catch(Exceptione){e.printStackTrace(System.err);}
Using that same table, my earlier approach using Jackcess' ImportUtil.importResultSet took about 3,100 ms to run (without having to create the destination table first)
connStr="jdbc:ucanaccess://C:/Users/Public/UCanAccessDemo.accdb";try(Connectionconn=DriverManager.getConnection(connStr)){StopWatchsw=newStopWatch();sw.start();StringdestinationPath="C:/Users/Gord/Desktop/target.accdb";StringtableName="TestData10k";try(Statements=conn.createStatement()){try(ResultSetrs=s.executeQuery("SELECT * FROM ["+tableName+"]")){// Jackcess calls:Databasedb=DatabaseBuilder.open(newFile(destinationPath));ImportUtil.importResultSet(rs,db,tableName);// create new table}}sw.stop();System.out.println(sw.getTime());}catch(Exceptione){e.printStackTrace(System.err);}
However, the following tweak to disable AutoSync reduced the Jackcess time to just over 300 ms
connStr="jdbc:ucanaccess://C:/Users/Public/UCanAccessDemo.accdb";try(Connectionconn=DriverManager.getConnection(connStr)){StopWatchsw=newStopWatch();sw.start();StringdestinationPath="C:/Users/Gord/Desktop/target.accdb";StringtableName="TestData10k";try(Statements=conn.createStatement()){try(ResultSetrs=s.executeQuery("SELECT * FROM ["+tableName+"]")){// Jackcess calls:Databasedb=newDatabaseBuilder().setAutoSync(false).setFile(newFile(destinationPath)).open();ImportUtil.importResultSet(rs,db,tableName);// create new tabledb.flush();}}sw.stop();System.out.println(sw.getTime());}catch(Exceptione){e.printStackTrace(System.err);}
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Apparently it cannot handle references to other tables -- yes the referenced table is already in the database and contains the referenced key. I works for a table that has no references but fails for others that do.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have submitted a Jackcess feature request for an option to let us insert arbitrary values into AutoNumber fields. The initial response was positive.
If the feature gets implemented then it should be possible to insert existing values into an AutoNumber field without having to resort to the above workarounds, with Jackcess at least. (How UCanAccess might do it depends on whether HSQLDB can be convinced to co-operate.)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Great! I hadn't tried prepared statements. Time for the copy is now down to 50 seconds.
But here's another issue. Copying this way regenerates keys (AutoID) in sequence from 1. In my source database table "A" there is some sparseness of the numbers because some items had been deleted. Now when I copy another table "B" that contains references to items in A. Those references are now in error. It gets
Upon converting from ODBC and MS Access Driver, I now cannot copy a table from a source database with the following SQL:
INSERT INTO TestInfo SELECT * FROM [ C:\Data\P81\LCAP.MDB ].[TestInfo]
The result is an exception: "invalid schema name: C__DATA_P81_LCAP_MDB"
How can I do this in UCanAccess/hsqldb?
If you aren't accessing to a second database you have just to establish another connection.
Also, if you want to use the same connection, you have to import the TestInfo table in the first database as linked table.
If it's the same database of your connection, you shouldn't use the schema name.
I didn't give you the full story. I have created a new database by copying a default with some constant tables and some empty tables to be filled in. Then I connect to the new db and begin to copy from an old (source) database into the new one to which I have established a connection in PocDatabase.connection. Below is one of the copy methods.
So, the variable source contains the location of the source database from which I want to copy the TestInfo table into the currently connected database.
I don't understand your statement "import the TestInfo table in the first database as linked table". What is a linked table?
Thanks for your patience and help.
Hi Wayne.
A linked table is a "virtual table" in an Access database file that points to a real table in another database file. For example, you can have a table named "TableA" in A.accdb, and you can create a linked table in B.accdb that points to that same table. Then in B.accdb you can refer to the linked table just like it was native to that file, but the information is actually retrieved from (and updates written to) the "real" table in A.accdb.
For more information, see the Microsoft Support article here.
Back on this subject, I need to be able to copy a complete table from another database. (A link will not do.) Is there an SQL statement that can do that, like the example I posted above? Or do I have to read from the source into a result set and then update the target database column by column and row by row (tedious)? Is there a document or website that defines the SQL standard used by this tool?
UCanaccess can't see database paths as schema whilst Access does it.
You can either follow the tedious approach above or an exciting mixed approach:
-get the ResultSet from the first database through UCanAccess
-get a jackcess connection to second database Database db = DatabaseBuilder.open(new File("my.mdb"));
-use the com.healthmarketscience.jackcess.ImportUtil method public static String importResultSet(ResultSet source,
Database db,
String name,
ImportFilter filter,
boolean useExistingTable)
throws SQLException,
IOException
-Please, let me know your findings: never tried.
Last edit: Marco Amadei 2015-03-24
Hi Marco. FWIW, I just tried the following code to copy a simple table
ID - Long Integer
TextField
DateField
MemoField
YesNoField
and it seems to have worked fine.
Last edit: Gord Thompson 2015-03-24
Ok, thank you!
For UcanAccess 3, I'm thinking if it may be possible to expose the access file in the same folder as schemas, as well as Access.
This would allow cross-database queries.
Last edit: Marco Amadei 2015-03-24
I have finally succeeded copying one of my large, complex databases using the "tedious" method referred to above. Here is a sample:
It works, BUT...
It takes forever!
With Java 7 and "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)}", using the INSERT INTO method cited in the original post, it took 9 seconds.
With Java 8 and "jdbc:ucanaccess://" it took 1655 seconds! That's unacceptable. What else can I do?
It looks like you're running in autocommit mode.
The use of a transaction instead,
connection.setAutocommit(false) before the loop
and
connection.commit() after the loop,
will drammatically improve the performance.
Should you face with memory issues (out of memory), just call connection.commit() each 5000/10000 records.
Please, let me know your results. Just a diamond is forever.
Last edit: Marco Amadei 2015-04-01
Thanks again, Marco.
Implementing your suggestion brought the time down to 200 seconds -- a BIG improvement from 1600, but still a big increase over 9.
The initial try ran out of memory, so I implemented a counter and committed after 5000 rows. Then it achieved the 200 second result.
Well, we can still improve drammatically.
Don't you use a scrollable ResultSet but a batch. I hope that's funny for you(SEE THE FINAL NOTE!!!!):
try (
THE FINAL NOTE: JUST BEFORE EACH COMMIT: stmtout.executeBatch();
PS: So doing you can also commit each 20000 rows.
It should take about 20s.
Please, let me know your results.
Last edit: Marco Amadei 2015-04-02
I did a couple of quick tests with a 5-column table containing 10,000 rows. I found that if I created the table structure in the destination database first, then the following code took about 1,600 ms to run:
Using that same table, my earlier approach using Jackcess'
ImportUtil.importResultSettook about 3,100 ms to run (without having to create the destination table first)However, the following tweak to disable AutoSync reduced the Jackcess time to just over 300 ms
Gord,
I tried your solution above. It does not copy into the existing (empty) table, it creates a new one with a "2" appended to the name.
Then I tried it by changing the importResultSet statement to use the existing table, like so:
That accomplished nothing, throwing a
Apparently it cannot handle references to other tables -- yes the referenced table is already in the database and contains the referenced key. I works for a table that has no references but fails for others that do.
Ah, yes. Access lets us insert arbitrary values into an AutoNumber column but Jackcess doesn't. Workarounds might include
Make the parent ID column
Number(Long Integer)instead ofAutoNumberin the destination table, orAdd code to track the mapping of old-to-new ID numbers in the parent table, then adjust the foreign key values in the child table(s) accordingly.
Last edit: Gord Thompson 2015-04-04
I have submitted a Jackcess feature request for an option to let us insert arbitrary values into AutoNumber fields. The initial response was positive.
If the feature gets implemented then it should be possible to insert existing values into an AutoNumber field without having to resort to the above workarounds, with Jackcess at least. (How UCanAccess might do it depends on whether HSQLDB can be convinced to co-operate.)
Great! I hadn't tried prepared statements. Time for the copy is now down to 50 seconds.
But here's another issue. Copying this way regenerates keys (AutoID) in sequence from 1. In my source database table "A" there is some sparseness of the numbers because some items had been deleted. Now when I copy another table "B" that contains references to items in A. Those references are now in error. It gets
Know of a work-around for that?