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.
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 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 ?
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.
I'm playing with the JDBC/MySQL 5.1. I created an insert query to insert some data into a table and want to return the generated key from the newly created row. However, when I go to reference the column by "id" which is my PK and auto-increment column.
PreparedStatement ps = St0rm.getInstance().getDatabase("main")
.prepare("INSERT INTO quests (name,minlevel,start_npc,end_npc) VALUES(?,?,?,?)", true); // creates a prepared statement with flag RETURN_GENERATED_KEYS
// ...
int affected = ps.executeUpdate();
ResultSet keys = ps.getGeneratedKeys();
if (affected > 0 && keys.next()) {
St0rm.getInstance().getLogger().warning(String.format("ID Column Name: %s", keys.getMetaData().getColumnName(1))); // says the column name is: GENERATED_KEY
q = new Quest(keys.getInt(1)); // column index from the generated key, no error thrown.
q = new Quest(keys.getInt("id")); // actual column name, line throws a SQLException
// ...
}
So, my question: Why does ResultSet.getGeneratedKeys use GENERATED_KEY as the column name?
You shouldn't retrieve these columns by name. Only by index, since
there can only ever be one column with MySQL and auto_increments that
returns value(s) that can be exposed by Statement.getGeneratedKeys().
Currently the MySQL server doesn't return information directly that
would make the ability to retrieve these columns by name in an
efficient manner possible, which is why I'm marking this as "to be
fixed later", since we can, once the server returns the information in
a way that the driver can use.
From here (in 2006!).
Here is the problem: At my company we have a large database that we want to perform some automated operations in it. To test that we got a small sample of that data about 6 10MB sized csv files. We want to use H2 to test the results of our program in it. H2 Seemed to work fine with our previous cvs though they were, at most, 1000 entries long. When it comes to any of our 10MB files the command
insert into myschema.mytable (select * from csvread('mycsvfile.csv'));
reports a failure because one of the registries is supposedly duplicated and offends our primary key constraints.
Unique index or primary key violation: "PRIMARY_KEY_6 ON MYSCHEMA.MYTABLE(DATETIME, LARGENUMBER, KIND)"; SQL statement:
insert into myschema.mytable (select * from csvread('src/test/resources/h2/data/mycsvfile.csv')) [23001-148] 23001/23001
Breaking the mycsvfile.csv into smaller pieces I was able to see that the problem starts to appear after about 10000 rows inserted(though the number varies depending on what data I used). I could however insert more than 10000 rows if I broke the file into pieces and then ran the command individually. But even if I manage to insert all that data manually I need an automated method to fill the database.
Since running the command would not give me the row that was causing the problem I guessed that the problem could be some cache in the csvread routine.
Then I created a small java program that could insert the data in the H2 database manually. No matter whether I batched the commands, closed and opened the connection for 1000 rows h2 reported that I was trying to duplicate an entry in the database.
org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY_KEY_6 ON MYSCHEMA.MYTABLE(DATETIME, LARGENUMBER, KIND)"; SQL statement:
INSERT INTO myschema.mytable VALUES ( '1997-10-06 01:00:00.0',25485116,1.600,0,18 ) [23001-148]
Doing a normal search for that registry using emacs I can find that the registry is not duplicated as the datetime column is unique in the whole dataset.
I cannot give that data for you to test since the company sells that information. But here is how my table definition is like.
create table myschema.mytable (
datetime timestamp,
largenumber numeric(8,0) references myschema.largenumber(largecode),
value numeric(8,3) not null,
flag numeric(1,0) references myschema.flag(flagcode),
kind smallint references myschema.kind(kindcode),
primary key (datetime, largenumber, kind)
);
This is how our csv looks like:
datetime,largenumber,value,flag,kind
1997-06-11 16:45:00.0,25485116,0.710,0,18
1997-06-11 17:00:00.0,25485116,0.000,0,18
1997-06-11 17:15:00.0,25485116,0.000,0,18
1997-06-11 17:30:00.0,25485116,0.000,0,18
And the java code that would fill our test database(forgive my ugly code, I got desperate :)
private static void insertFile(MyFile file) throws SQLException {
int updateCount = 0;
ResultSet rs = Csv.getInstance().read(file.toString(), null, null);
ResultSetMetaData meta = rs.getMetaData();
Connection conn = DriverManager.getConnection(
"jdbc:h2:tcp://localhost/mytestdatabase", "sa", "pass");
rs.next();
while (rs.next()) {
Statement stmt = conn.createStatement();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < meta.getColumnCount(); i++) {
if (i == 0)
sb.append("'" + rs.getString(i + 1) + "'");
else
sb.append(rs.getString(i + 1));
sb.append(',');
}
updateCount++;
if (sb.length() > 0)
sb.deleteCharAt(sb.length() - 1);
stmt.execute(String.format(
"INSERT INTO myschema.mydatabase VALUES ( %s ) ",
sb.toString()));
if (updateCount == 1000) {
conn.close();
conn = DriverManager.getConnection(
"jdbc:h2:tcp://localhost/mytestdatabase", "sa", "pass");
updateCount = 0;
}
}
if (!conn.isClosed()) {
conn.close();
}
rs.close();
}
I'll be glad to provide more information if requested.
EDIT
#Randy I always check if the database is clean before running the command and in my java program I have a routine to delete all data from a file that fails to be inserted.
select * from myschema.mytable where largenumber = 25485116;
DATETIME LARGENUMBER VALUE FLAG KIND
(no rows, 8 ms)
The only thing that I can think of is that there is a trigger on the table that sets the timestamp to "now". Although that would not explain why you are successful with a few rows, it would explain why the primary key is being violated.