I am building a java program to insert data to my oracle database.
My problem is that I need to insert into two tables, and to reach unique rows I use in TABLE_A triggers for id before insert get next val in a sequence.
But i need the same id for the TABLE_B for connection.
( i cant get getval because what if another user uses the program... )
So I need to reach somehow that when I use executeql(sql) command in return I see what I have submit.
Now I use that I have name and date, so I select the id where name and date is the just inserted.
But its not the best because in one day I can insert more names. So now this will not unique.
like :
insert into table a ( name,date) val ( 'Ryan','2014.01.01')
id here is autoincremented by sequence
than another sql run:
inert into table_b ( id,someval) val ( select id from table_a where
name ='Ryan', date='2014.01.01, 23)
so i need something like:
system.out.println(smtp.executesql(sql).whatIinsertednow())
*than console:* '1 row insered (id,name,date) : ( 1, Ryan, 2014.01.01)
PreparedStatement prepareStatement = connection.prepareStatement("insert...",
new String[] { "your_primary_key_column_name" });
prepareStatement.executeUpdate();
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if (null != generatedKeys && generatedKeys.next()) {
Long primaryKey = generatedKeys.getLong(1);
}
I have found the answer this is perfectly works. I can insert from JAVA and its return with the key.
Full version:
CREATE TABLE STUDENTS
(
STUDENT_ID NUMBER NOT NULL PRIMARY KEY,
NAME VARCHAR2 (50 BYTE),
EMAIL VARCHAR2 (50 BYTE),
BIRTH_DATE DATE
);
CREATE SEQUENCE STUDENT_SEQ
START WITH 0
MAXVALUE 9999999999999999999999999999
MINVALUE 0;
And the Java code
String QUERY = "INSERT INTO students "+
" VALUES (student_seq.NEXTVAL,"+
" 'Harry', 'harry#hogwarts.edu', '31-July-1980')";
// load oracle driver
Class.forName("oracle.jdbc.driver.OracleDriver");
// get database connection from connection string
Connection connection = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:sample", "scott", "tiger");
// prepare statement to execute insert query
// note the 2nd argument passed to prepareStatement() method
// pass name of primary key column, in this case student_id is
// generated from sequence
PreparedStatement ps = connection.prepareStatement(QUERY,
new String[] { "student_id" });
// local variable to hold auto generated student id
Long studentId = null;
// execute the insert statement, if success get the primary key value
if (ps.executeUpdate() > 0) {
// getGeneratedKeys() returns result set of keys that were auto
// generated
// in our case student_id column
ResultSet generatedKeys = ps.getGeneratedKeys();
// if resultset has data, get the primary key value
// of last inserted record
if (null != generatedKeys && generatedKeys.next()) {
// voila! we got student id which was generated from sequence
studentId = generatedKeys.getLong(1);
}
}
source : http://viralpatel.net/blogs/oracle-java-jdbc-get-primary-key-insert-sql/
You can accomplish that by using the RETURNING clause in your INSERT statement:
INSERT INTO table_a ( name,date) val ( 'Ryan','2014.01.01') RETURNING id INTO ?
Related
I have a very simple table that is in both MySQL and DB2 called STUDENT. The columns are: ID (primary key, auto incrementing), FIRST_NAME, LAST_NAME, AGE.
The table is replicated in both databases, so they should be the same syntactically. However, I have spent the entire day trying to figure out why, when I write a simple Java program to insert into the database, the MySQL version returns back the generated key via PreparedStatement.getGeneratedKeys(), while the DB2 version does not return anything.
My code looks like:
String sql = "INSERT INTO STUDENT (FIRST_NAME, LAST_NAME, AGE) VALUES ('Jacob', 'Eldy', 19)"
final Connection connection = getConnection(dataSource.get());
int[] insertedRows = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.addBatch();
insertedRows = ps.executeBatch();
rs = ps.getGeneratedKeys();
while(rs.next()) {
LOGGER.info(rs.getString(1));
}
connection.commit();
} catch (Exception e) {
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
} finally {
close(ps, connection);
}
After committing the connection for both databases DB2 and MySQL, both actually show the row being inserted, and the more I insert, a new row appears with an auto incremented ID, however only the MySQL database has a value in while(rs.next()), the DB2 version just skips over it since it is empty.
Am I doing something wrong? Is this just an incompatibility issue with DB2 and it just does not return the generated value? If so, what would be the best solution for tackling this issue?
UPDATE, adding the two DDLs for DB2 & mySQL:
mySQL DDL:
CREATE TABLE 'STUDENT'
...
`ID` int NOT NULL AUTO_INCREMENT
PRIMARY KEY('ID')
AUTO_INCREMENT=19073
DB2 DDL:
CREATE TABLE STUDENT
(
ID INTEGER DEFAULT IDENTITY GENERATED ALWAYS NOT NULL
PRIMARY KEY (ID)
)
CREATE TABLE STUDENT
(
ID INT NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
, FIRST_NAME VARCHAR (20)
, LAST_NAME VARCHAR (20)
, AGE SMALLINT
);
The following code based on the Making batch updates in JDBC applications links (this one is for Db2 for LUW) provided by others works as expected with the table definition above:
PreparedStatement ps = con.prepareStatement
(
"INSERT INTO STUDENT (FIRST_NAME, LAST_NAME, AGE) " +
"VALUES (?,?,?)"
, Statement.RETURN_GENERATED_KEYS
);
ps.setString (1, "Jacob");
ps.setString (2, "Eldy");
ps.setShort (3, (short) 19);
ps.addBatch();
ps.setString (1, "Jacob");
ps.setString (2, "Eldy");
ps.setShort (3, (short) 19);
ps.addBatch();
int [] numUpdates = ps.executeBatch();
for (int i=0; i < numUpdates.length; i++)
if (numUpdates[i] == Statement.SUCCESS_NO_INFO)
System.out.println("Execution " + i + ": unknown number of rows updated");
else
System.out.println("Execution " + i + " successful: " + numUpdates[i] + " rows updated");
ResultSet[] resultList = ((com.ibm.db2.jcc.DB2PreparedStatement) ps).getDBGeneratedKeys();
if (resultList.length != 0)
for (int i = 0; i < resultList.length; i++)
{
while (resultList[i].next())
System.out.println("Automatically generated key value = " + resultList[i].getBigDecimal(1));
resultList[i].close();
}
else
System.out.println("Error retrieving automatically generated keys");
Am I doing something wrong? Is this just an incompatibility issue with DB2 and it just does not return the generated value? If so, what would be the best solution for tackling this issue?
Yes, you are doing wrong. It's not incompatibility issue, and it's not an issue. DB2 is different than MySQL. You can't handle both because you have incompatible DDL. Since no records are inserted into DB2 the value of the key is not available.
The solution to the issue is to create a trigger on insert a record to make sure the primary key is inserted into DB. If you are missing a key then select it from the sequence and substitute the value.
Now if identity is generated into DB2 like this
CREATE TABLE STUDENT
(
ID INTEGER DEFAULT IDENTITY GENERATED ALWAYS NOT NULL
PRIMARY KEY (ID)
)
So it will always return getGeneratedKeys().
I am forced to use createSQLQuery to insert values into tables with an Identity column (the first column and the primary key) using hibernate. Using hibernate classes are not an option since the tables are created on the fly for each customer that is added to the system. I have run the query and it successfully inserts into the table. I then execute a "select scope_identity()" and it always returns null. "select ##Identity" works but that is not guaranteed to be the correct one. I have also tried to append "select scope_identity()" to the insert query. Then I tried query.list() and query.uniqueResult() both of which throw the hibernate exception of "No Results ..."
Session session = DatabaseEngine.getSessionFactory().openSession();
String queryString = "insert into table1 (dataid) values (1)"
SQLQuery query = session.createSQLQuery(insertQueryString);
query.executeUpdate();
query = session.createSQLQuery("select scope_identity()");
BigDecimal entryID = (BigDecimal)query.uniqueResult();
The simple example table is defined as follows:
"CREATE TABLE table1 (EntryID int identity(1,1) NOT NULL," +
"DataID int default 0 NOT NULL, " +
"PRIMARY KEY (EntryID))";
Is there a way I am missing to use scope_identity() with createSQLQuery?
Actually the SQLServerDialect class used by Hibernate uses the same "scope_identity()" too.
The reason why it's not working is because you need to execute those in the same statement or stored procedure.
If you execute the scope_identity() call in a separate statement, SQL Server will not be able to give you last inserted identity value.
You cannot do it with the SQLQuery, even Hibernate uses JDBC to accomplish this task. I wrote a test on GitHub to emulate this and it works like this:
Session session = entityManager.unwrap(Session.class);
final AtomicLong resultHolder = new AtomicLong();
session.doWork(connection -> {
try(PreparedStatement statement = connection.prepareStatement("INSERT INTO post VALUES (?) select scope_identity() ") ) {
statement.setString(1, "abc");
if ( !statement.execute() ) {
while ( !statement.getMoreResults() && statement.getUpdateCount() != -1 ) {
// do nothing until we hit the resultset
}
}
try (ResultSet rs = statement.getResultSet()) {
if(rs.next()) {
resultHolder.set(rs.getLong(1));
}
}
}
});
assertNotNull(resultHolder.get());
The code uses Java 8 lambdas instead of anonymous classes, but you can easily port it to Java 1.7 too.
How do I insert a generated random integer from java and insert into MySQL as unique id?
generate random number
Random rand = new Random();
int x = rand.nextInt(100000);
before storing to database you have to check that number is already stored or not.
after checking that you can insert.
why do you insert random number as a unique id?.you can auto increment your primary key.then you can easily insert unique number for you primary key.and no need to create random number.
You could do it inverse: use an AUTOINCREMENT primary key on the table and per JDBC do not insert that primary key, but afterwards query the key generated by MySQL, concurrency safe.
try (PreparedStatement stm = conn.prepareStatement(
"INSERT INTO moviesTbl (title, ...) VALUES(?, ? ...)")) {
stm.setString(1, title);
stm.setString(2, ...);
...
int updateCount = stm.executeUpdate();
if (updateCount != 0) {
try (ResultSet genKeys = stm.getGeneratedKeys()) {
if (genKeys.next()) { // At most 1 record inserted
// Normally only one key generated per record.
int generatedId = genKeys.getInt(0);
...
}
} // Close result set.
}
} // Closes stm
JDBC returns a ResultSet as you could have inserted several records. And then you could have several generated keys per record.
Storing a UUID has not a full support in MySQL; maybe that the JDBC driver has support already.
A UUID is a 128 bit number, MaySQL BINARY(16), or CHAR(36) with something like this
CREATE FUNCTION `BINTOUUID`(UUID BINARY(16)) RETURNS char(36)
BEGIN
RETURN concat(HEX(LEFT(uuid,4)),'-', HEX(MID(uuid,5,2)),'-', HEX(MID(uuid,7,2)),
'-',HEX(MID(uuid,9,2)),'-',HEX(RIGHT(uuid,6)));
END
As I think you do not mean this, I leave it at that.
Having following code, how do I know if the execute() method resulted in insert or in update?:
Connection c = DriverManager.getConnection(connectionString);
PreparedStatement st = c.prepareStatement("INSERT INTO `table`(`field1`) VALUES (?) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id);");
st.setString(1,"some value");
st.execute();
Thanks in advance.
Consider the following MySQL test table:
CREATE TABLE `customers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
with existing sample data as follows:
id name email
-- -------------- ----------------
1 Loblaw, Bob bob#example.com
2 Thompson, Gord gord#example.com
With the default connection setting compensateOnDuplicateKeyUpdateCounts=false (described here) the following Java code
PreparedStatement ps = dbConnection.prepareStatement(
"INSERT INTO customers (name, email) " +
"VALUES (?, ?) " +
"ON DUPLICATE KEY UPDATE " +
"name = VALUES(name), " +
"id = LAST_INSERT_ID(id)");
ps.setString(1, "McMack, Mike");
ps.setString(2, "mike#example.com");
int euReturnValue = ps.executeUpdate();
System.out.printf("executeUpdate returned %d%n", euReturnValue);
Statement s = dbConnection.createStatement();
ResultSet rs = s.executeQuery("SELECT LAST_INSERT_ID() AS n");
rs.next();
int affectedId = rs.getInt(1);
if (euReturnValue == 1) {
System.out.printf(" => A new row was inserted: id=%d%n", affectedId);
}
else {
System.out.printf(" => An existing row was updated: id=%d%n", affectedId);
}
produces the following console output
executeUpdate returned 1
=> A new row was inserted: id=3
Now run the same code again with the parameter values
ps.setString(1, "Loblaw, Robert");
ps.setString(2, "bob#example.com");
and the console output is
executeUpdate returned 2
=> An existing row was updated: id=1
This demonstrates that .executeUpdate really can return 2 if the unique index causes an existing row to be updated. If you require further assistance with your actual test code then you should edit your question to include it.
Edit
Further testing reveals that .executeUpdate will return 1 if
the attempted INSERT is aborted because it would result in a duplicate UNIQUE key value, and
the specified ON DUPLICATE KEY UPDATE changes do not actually modify any values in the existing row.
This can be confirmed by running the above test code twice in a row with the exact same parameter values. Note that the UPDATE ... id = LAST_INSERT_ID(id) "trick" does ensure that the correct id value is returned.
That probably explains OP's test results if the only value being inserted was the UNIQUE key value.
Use executeUpdate instead as it returns an int row count.
UPDATE 1: According to the MySQL INSERT ... ON DUPLICATE KEY UPDATE documentation:
With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if
the row is inserted as a new row, and 2 if an existing row is updated.
UPDATE 2: INSERT IGNORE may also be an option:
INSERT IGNORE INTO `table`(`field1`) VALUES (?)
executeUpdate should return 1 when a new row is inserted and 0 when there is a duplicate.
I am inserting into a table from my jdbc program,
like this
PreparedStatement ps = con.prepareStatement(sqlqry);
ps.setInt(1,dto.getInstall_id());
ps.setString(2, dto.getDashboard_name());
ps.setString(3, dto.getDashboard_type());
ps.setString(4, dto.getDashboard_image());
But in the table i have column say D_ID which in is primary key and i dont want o insert the D_ID from my program into table because the same id might be already exist. So for avoiding the PK_CONSTRAINT I am not inseting it.
But when i try this i am getting this error.
ORA-01400: cannot insert NULL into ("TESTDB"."TESTATBLE"."D_ID")
So how can i solve this problem, Any alternative like if i insert D_ID from the program my JDBC program the D_ID column should dynamically generate id's in the table.
I am banging my head for this. Please help!
You should create that ID using a sequence. So for each ID column that you have, you create a corresponding sequence:
create table testatble
(
d_id integer not null primary key,
install_id integer not null,
dashboard_name varchar(100)
... more columns ....
);
create sequence seq_testatble_d_id;
You can use it like this:
// note that there is no placeholder for the D_ID column
// the value is taken directly from the sequence
String sqlqry =
"insert into testatble (d_id, install_id, dashboard_name) " +
"values (seq_testatble_d_id.nextval, ?, ?)";
PreparedStatement ps = con.prepareStatement(sqlqry);
ps.setInt(1,dto.getInstall_id());
ps.setString(2, dto.getDashboard_name());
... more parameters ...
ps.executeUpdate();
That way the id will be generated automatically.
If you need the generated ID in your Java code after the insert, you can use getGeneratedKeys() to return it:
// the second parameter tells the driver
// that you want the generated value for the column D_ID
PreparedStatement ps = con.prepareStatement(sqlqry, new String[]{"D_ID"});
// as before
ps.setInt(1,dto.getInstall_id());
ps.setString(2, dto.getDashboard_name());
... more parameters ...
ps.executeUpdate();
// now retrieve the generated ID
int d_id = -1;
ResultSet rs = ps.getGeneratedKeys();
if (rs.next()) // important!
{
d_id = rs.getInt(1);
}
rs.close();
More on sequences in the Oracle manual: http://docs.oracle.com/cd/E11882_01/server.112/e26088/pseudocolumns002.htm#SQLRF00253
You should use Auto Increment number for ID(I Oracle you can use sequence). You can do this at the link:
Create ID with auto increment on oracle
You should also read this. If there is a sequence to your ID then here you can read information about that.