DdlUtils: defering insertion - java

in order to migrate a db from oracle to mysql i am using ddlutils. Migrating the schema works for my purposes, but inserting the data fails due to missing rows. The following excerpt from the log file explains it:
[ddlToDatabase] About to execute SQL: INSERT INTO `RECORDSTATUS` (`NAME_ID`, RECORDSTATUS_ID`, `NAME`, `SORTVALUE`) VALUES (?, ?, ?, ?)
[ddlToDatabase] Inserted bean RECORDSTATUS:RECORDSTATUS_ID=0
...
[ddlToDatabase] Defering insertion of row NAME:LANGUAGE_ID=0;NAME_ID=5941 because it is waiting for:
[ddlToDatabase] RECORDSTATUS:RECORDSTATUS_ID=0
In the database, there is a row RECORDSTATUS_ID=0. Did anybody face the same issue? Has somebody an idea, what the problem is?

I had similar problem when migrating from MySql to DerbyDB. I my case the actual problem was that DDLUtils handles only those foreign keys that are targetted to primary keys.
So, if you have MASTER table that contains some unique non primary key field, and you have DETAILS table that references (foreign key) to that unique non primary key field, DDLUtils cannot link DETAILS records to MASTER and cannot therefore insert DETAIL records at all.
This was the situation in DDLUtils version 1.0.
I made some quick (and mayby dirty) modifications to code and it seems to solve this problem. Modified version can be downloaded here (includes source): DllUtils-1.0_mod_with_src.jar. You can use it at you own risk.
Best regards
Kari Surakka

INSERT INTO `RECORDSTATUS` (`NAME_ID`, RECORDSTATUS_ID`, `NAME`, `SORTVALUE`) VALUES
should be:
INSERT INTO `RECORDSTATUS` (`NAME_ID`, `RECORDSTATUS_ID`, `NAME`, `SORTVALUE`) VALUES

Related

Doing an INSERT ALL using JDBC in ORACLE

I am using Oracle Database 12c Enterprise Edition
I want to insert records into 2 tables say TABLE1 and TABLE2 back to back using JDBC. These 2 tables have a primary key and foreign key relationship based on a common column say ID_COLUMN
I am planing to use the following single query and fire it via my Java application via JDBC:
insert all
into TABLE1 (ID_COLUMN,COL2,COL3,COL4,COL5,COL6) values(?,?,?,?,?,?)
into TABLE2 (COL1_1,COL_1_2,COL_1_3,ID_COLUMN) values('blah',42,'rubbish',
select test_ctrl.seq_test_id.nextval FROM dual)
select * from dual;
My basic requirement is that I need to INSERT TABLE2 with the latest ID_COLUMN from TABLE1 from my current session.
I know the usage of select test_ctrl.seq_test_id.nextval FROM dual in the INSERT ALL statement is not correct. But it being Oracle I cant use SCOPE_IDENTITY()
Please suggest how can I make this query work
"But it being Oracle I cant use SCOPE_IDENTITY()"
Ah but you can. In Oracle 12c they introduced identity columns: these are a special variant of virtual columns.
create table my_table (
id number generated always as identity
....
, constraint my_table_pk primary key (id)
Find out more.
I seem to have found out the answer to my question.Modified the query like this.Please take note of edme_ctrl.seq_ts_annotation_id.nextval and edme_ctrl.seq_ts_annotation_id.currval
INSERT ALL INTO "SPI7CG_CgNvI".X$ANNOTATIONS(ANNOTATION_ID,CATEGORY,REASON,COMMENTS,AUTHOR,ADJUSTMENT_TYPE,ADJUSTMENT_VALUE) VALUES (edme_ctrl.seq_ts_annotation_id.nextval, '51','33','Test Bulk Insert','kshiam','A',10) INTO "SPI7CG_CgNvI".X$DATA_ANNOTATIONS(ANNOTATION_ID, TABLE_NAME, TABLE_ROW_ID,COLUMN_NAME) VALUES (edme_ctrl.seq_ts_annotation_id.currval,'W$XXXXXGNVBSNSSNDCTRSSR007',164921155,'IVXXXXXGNVBXWGSQDTWQRTR0003') select * from dual

Ignore duplication constraints when bulk inserting into Postgresql or MySQL

When issuing a bulk insert statement, how can we ignore (supress) the exception thrown by DB and/or JDBC driver ?
Lets say I want to bulk insert some Users and I have an Id as a unique key
INSERT INTO users
(id,name,age,email,pass_code)
VALUES
(1,'Mark',18,'mail#mail.com',123),
(2,'Zak',18,'mail#mail.com',123),
(3,'Djigi',18,'mail#mail.com',123),
(1,'James Petkov',18,'mail#mail.com',123), --Duplicated by id ?
(4,'Kinkinikin',18,'mail#mail.com',123),
(5,'A bula bula ',18,'mail#mail.com',123),
(6,'Shakazulo',18,'mail#mail.com',123);
How to tell the engine MySQL/PostgreSQL to continue inserting the remaining records ?
Is this supported in SQL at all ?
In PostgreSQL, you can ignore the failing rows with
INSERT ... ON CONFLICT (id) DO NOTHING;
A more general solution is to run each INSERT separately and ignore errors.

Create table with primary key using jOOQ

jOOQ has CREATE TABLE syntax as stated in the documentation:
create.createTable(AUTHOR)
.column(AUTHOR.ID, SQLDataType.INTEGER)
.column(AUTHOR.FIRST_NAME, SQLDataType.VARCHAR.length(50))
.column(AUTHOR_LAST_NAME, SQLDataType.VARCHAR.length(50))
.execute();
I'm wondering how to define which column belongs to the primary key? So is there a way in jOOQ to create a CREATE TABLE statement with PRIMARY KEY information?
I'm specifically interested in a solution for SQLite, which doesn't have syntax to add the primary key afterwards, so I think in worst case I have to go to a DB specific solution?
This feature has been implemented for jOOQ 3.8: #4050.
create.createTable(AUTHOR)
.column(AUTHOR.ID, SQLDataType.INTEGER)
.column(AUTHOR.FIRST_NAME, SQLDataType.VARCHAR.length(50))
.column(AUTHOR_LAST_NAME, SQLDataType.VARCHAR.length(50))
.constraints(
constraint("PK_AUTHOR").primaryKey(AUTHOR.ID)
)
.execute();
Since jOOQ 3.6 (#3338), you can also use the ALTER TABLE statement to add a constraint after creating the table:
create.alterTable(AUTHOR)
.add(constraint("PK_AUTHOR").primaryKey(AUTHOR.ID))
.execute();

Can I SELECT with LAST_INSERT_ID() after INSERT Batch without any cares?

I'm asking myself if it is possible to SELECT with LAST_INSERT_ID() in WHERE Clause after an batch of INSERTs without getting corrupt data in the tables? I'm thinking of the scenario that multiple users doing the same stuff at the same time. I develop an JSF Application in which this scenario can be possible.
In hard Code my SELECT after INSERTs looks like this:
preparedstatement.addBatch(
"INSERT INTO table1(all the FIELDS)"
+ "VALUES(null, ...);"
);
preparedstatement.addBatch(
"INSERT INTO table2(all the FIELDS)"
+ "VALUES(null, LAST_INSERT_ID(), ...);"
);
preparedstatement = connect.prepareStatement(
"SELECT id FROM table3 WHERE id = LAST_INSERT_ID();"
);
preparedstatement.executeBatch();
resultSet = preparedstatement.executeQuery();
Get I problems with this implementation or is there an better way?
Best Regards
You should be fine, quoting MySQL's documentation:
The ID that was generated is maintained in the server on a
per-connection basis. This means that the value returned by the
function to a given client is the first AUTO_INCREMENT value generated
for most recent statement affecting an AUTO_INCREMENT column by that
client. This value cannot be affected by other clients, even if they
generate AUTO_INCREMENT values of their own. This behavior ensures
that each client can retrieve its own ID without concern for the
activity of other clients, and without the need for locks or
transactions.
MySQL Last_insert_id

Can't update Oracle IOT table with jbdc updateRow method

I have Oracle 10gR2 database with IOT table within:
create table countries (
id number primary key,
name varchar2(30) not null enable
) organization index;
I try to update table values with this Java (version 1.6) code:
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
ResultSet src = stmt.executeQuery("select id, name from countries");
src.next();
src.updateString("name", "__test__");
src.updateRow();
But updateRow throws SQLException (ORA-01410: invalid ROWID). If I try to update a heap (ordinary) table - all works.
I have use this code with different versions of oracle drivers (from here http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc_10201.html)
After some research I have detected that IOT and HEAP table have different format of rowids:
IOT example *BAJzKgwCwRb+
HEAP example AAAbgVAAJAAMyr8AAA
But I still don't know how to solve this problem. Are you have any ideas?
Can you get the results of an extended SQL trace of your query to see what JDBC's doing under the covers? I suspect it's attempting to do
UPDATE COUNTRIES SET NAME = '__TEST__' WHERE ROWID = :rowid_fetched
and ROWID means something totally different in Oracle IOT's; it's not the immutable address of a row, but a guess as to the path to the row.
My recommendation as to how to do this is to propagate a system-generated timestamp field onto all of your tables, and use that for concurrency control rather than declaring an updatable recordset -- which will take and hold locks for every record in the recordset.
Then your application would fetch the rowset as normal, but issue statements like:
UPDATE COUNTRIES SET NAME = '__TEST__' WHERE MOD_TS = :mod_ts_fetched
to give stateless optimistic locking.
Looks like your table does not really need to be IOT. I would suggest you recreate it as a normal table and add index on both ID and name. Same performance, same logic, no ROWID problem.

Categories

Resources