I have the code as follows:
DatabaseMetaData dmd = connection.getMetaData();
ResultSet rs = dmd.getPrimaryKeys(null, null, tableName);
while(rs.next()){
primaryKey = rs.getString("COLUMN_NAME");
}
rs is not null while rs.next() always return false, anyone has idea about it? Thanks.
metadata interface implementation was implemented by driver vendors. It may not be supported by some driver and some db.
Here is text from javadoc:
Some DatabaseMetaData methods return lists of information in the form of ResultSet objects. Regular ResultSet methods, such as getString and getInt, can be used to retrieve the data from these ResultSet objects. If a given form of metadata is not available, an empty ResultSet will be returned.
table name is case sensitive in oracle
or try the below approach
DatabaseMetaData dm = conn.getMetaData( );
ResultSet rs = dm.getExportedKeys( "" , "" , "table1" );
while( rs.next( ) )
{
String pkey = rs.getString("PKCOLUMN_NAME");
System.out.println("primary key = " + pkey);
}
you can also use getCrossReference or getImportedKeys to retrieve primary key
Related
I am Retrieving some tables from database and storing those table names in a hashset. Code I am using to retrieve table is as follows
DatabaseMetaData md = conn.getMetaData();
ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
hash. add(rs. getString(3) ) ;
}
Now I have tables in a hash set.
Now I want to retrieve data from all these tables in a hash set for particular column 'student'. And put all values in a list. I want to retrieve all distinct values of column student in all these tables. Table may contain or may not contain this student column. If a table contains this column then I want to store its distinct values in a list. Please suggest how to do it.
Note that you can not extract table data using the databasemetadata. Databasemetadata will only provide you the details of table like name, columns, datatypes etc. You need to make the JDBC connection with the database and then need to fire the select query to get the desired result.
Below is the simple JDBC program to do so:
DatabaseMetaData md = conn.getMetaData();
// get tables from database
ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
hash. add(rs. getString(3) ) ;
}
// getColumns of table 'tableName'
ResultSet rs2 = md.getColumns(null, null, tableName, null);
boolean found = false;
while (rs2.next()) {
String columnName = rs2.getString("COLUMN_NAME");
if (columnName.equalsIgnoreCase("student")) {
found = true;
break;
}
}
if (found) {
String driver = "provide the driver for database here like com.mysql.....";
String url = "provide the connection url here like jdbc://...."
String userName = "provide DB username"
String password = "provide DB username"
Class.forName(driver)
Connection conn = DriverManager.getConnection(url, userName, password)
Statement st = conn.createStatement();
Resultset rs3 = null;
// Now take the tableName from your hashset and pass it into below query.
String query = "select student from " + tableName;
rs3 = st.executeQuery(query);
While(rs3.next()) {
// Store the results anywhere you want by obtaining 'rs3.getString(1)'
}
}
Hope this resolves your problem. Please ignore typos in code if any.
Trying to understand what is going on here. DatabaseMetaData is returning an empty result set, where as an SQL query that is effectively the same does not. Not a major issue as I am using the second code example as a work around.
DatabaseMetaData dmd = this.connection.getMetaData();
ResultSet rs = dmd.getSchemas();
while (rs.next()){
// empty result set
}
Expected a non-empty result set.
ResultSet rs = this.connection.prepareStatement("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA;").executeQuery();
while (rs.next()){
// non-empty result set with expected results
}
Expected a non-empty result set and got it.
As far as I can tell the MySQL JDBC driver considers that a catalog, not a schema. So you should use getCatalogs instead (and everywhere you use it, you need to use the catalog parameter, not the schema parameter).
The getSchemas method in Connector/J always returns an empty result set:
public java.sql.ResultSet getSchemas() throws SQLException {
Field[] fields = new Field[2];
fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
fields[1] = new Field("", "TABLE_CATALOG", java.sql.Types.CHAR, 0);
ArrayList<ResultSetRow> tuples = new ArrayList<ResultSetRow>();
java.sql.ResultSet results = buildResultSet(fields, tuples);
return results;
}
The getCatalogs returns the result of SHOW DATABASES. And in DatabaseMetaDataUsingInfoSchema you see the TABLE_SCHEMA column of the information schema aliased as TABLE_CAT (for catalog) and the catalog parameter being passed as a value for the TABLE_SCHEMA column in the query:
String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME,"
+ "COLUMN_NAME, NULL AS GRANTOR, GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE "
+ "TABLE_SCHEMA LIKE ? AND TABLE_NAME =? AND COLUMN_NAME LIKE ? ORDER BY COLUMN_NAME, PRIVILEGE_TYPE";
java.sql.PreparedStatement pStmt = null;
try {
pStmt = prepareMetaDataSafeStatement(sql);
if (catalog != null) {
pStmt.setString(1, catalog);
} else {
pStmt.setString(1, "%");
}
pStmt.setString(2, table);
pStmt.setString(3, columnNamePattern);
I realize this is an old post, but it comes up in a Google search on this topic, and the answer here did not work for me.
After much more digging, I found the correct way to do this.
First, you can get a list of all the metadata table types by doing this
DatabaseMetaData metaData = connection.getMetaData();
ResultSet rs = metaData.getTableTypes();
while (rs.next()) {
System.out.println(rs.getString(1));
}
The table type that we are interested in is simply called TABLE.
And this code will pull up all the names of the schema's in the SQL server, assuming your credentials have the rights to view them.
DatabaseMetaData metaData = connection.getMetaData();
ResultSet rs = metaData.getTables(null, null, null, new String[]{"TABLE"});
while(rs.next())
{
System.out.println(rs.getString(1));
}
It worked for me anyways with Java 8 and mysql-connector-java-8.0.22
I am using Statement.RETURN_GENERATED_KEYS flag to obtan the newly generated primary key value after every insert in the database.
Here is the code snippet:
Connection conn = null;
conn = getDBConnection(); //Susseccfully returns a proper Connection object
PreparedStatement stmt = null;
String sql = "INSERT INTO ..."; //Proper error free INSERT query
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);//to obtain the new primary key
i = stmt.executeUpdate();//the value of i is always 1 :(
Not able to understand why this is happening. My driver is com.mysql.jdbc.Driver
EDIT: The primary key's data tyoe is BIGINT in the DB and its the second column in the table.
executeUpdate() returns the number of affected rows.
Call stmt.getGeneratedKeys() to get a ResultSet with the generated keys:
long key = -1L;
PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);//to obtain the new primary key
// execute statement
int affectedRows = stmt.executeUpdate();
ResultSet rs = stmt.getGeneratedKeys();
// get generated key
if (rs != null && rs.next()) {
key = rs.getLong(1);
}
This question already has answers here:
How to get a value from the last inserted row? [duplicate]
(14 answers)
Closed 9 years ago.
Is there some way to get a value from the last inserted row?
I am inserting a row where the PK will automatically increase due to sequence created, and I would like to get this sequence number. Only the PK is guaranteed to be unique in the table.
I am using Java with a JDBC and Oracle.
I forgot to add that I would like to retrieve this value using the resultset below. (I have tried this with mysql and it worked successfully, but I had to switch over to Oracle and now I get a string representation of the ID and not the actually sequence number)
Statement stmt = conn.createStatement();
stmt.executeUpdate(insertCmd, Statement.RETURN_GENERATED_KEYS);
stmt.RETURN_GENERATED_KEYS;
ResultSet rs = stmt.getGeneratedKeys();
if(rs.next()){
log.info("Successful insert");
id = rs.getString(1);
}
The above snippet would return the column int value stored in a mysql table. But since I have switched over to Oracle, the value returned is now a strange string value.
What you're trying to do is take advantage of the RETURNING clause. Let's setup an example table and sequence:
CREATE TABLE "TEST"
( "ID" NUMBER NOT NULL ENABLE,
"NAME" VARCHAR2(100 CHAR) NOT NULL ENABLE,
CONSTRAINT "PK_TEST" PRIMARY KEY ("ID")
);
CREATE SEQUENCE SEQ_TEST;
Now, your Java code should look like this:
String insertSql = "BEGIN INSERT INTO TEST (ID, NAME) VALUES (SEQ_TEST.NEXTVAL(), ?) RETURNING ID INTO ?; END;";
java.sql.CallableStatement stmt = conn.prepareCall(insertSql);
stmt.setString(1, "John Smith");
stmt.registerOutParameter(2, java.sql.Types.VARCHAR);
stmt.execute();
int id = stmt.getInt(2);
This is not consistent with other databases but, when using Oracle, getGeneratedKeys() returns the ROWID for the inserted row when using Statement.RETURN_GENERATEDKEYS. So you need to use the oracle.sql.ROWID proprietary type to "read" it:
Statement stmt = connection.createStatement();
stmt.executeUpdate(insertCmd, Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
oracle.sql.ROWID rid = (oracle.sql.ROWID) rs.getObject(1);
But this won't give you the generated ID of the PK. When working with Oracle, you should either use the method executeUpdate(String sql, int[] columnIndexes) or executeUpdate(String sql, String[] columnNames) instead of executeUpdate(String sql, int autoGeneratedKeys) to get the generated sequence value. Something like this (adapt the value to match the index or the name of your primary key column):
stmt.executeUpdate(INSERT_SQL, new int[] {1});
ResultSet rs = stmt.getGeneratedKeys();
Or
stmt.executeUpdate(INSERT_SQL, new String[] {"ID"});
ResultSet rs = stmt.getGeneratedKeys();
While digging a bit more on this, it appears that this approach is shown in the Spring documentation (as mentioned here) so, well, I guess it can't be totally wrong. But, unfortunately, it is not really portable and it may not work on other platforms.
You should use ResultSet#getLong() instead. If in vain, try ResultSet#getRowId() and eventually cast it to oracle.sql.ROWID. If the returned hex string is actually the ID in hexadecimal flavor, then you can try converting it to decimal by Long#valueOf() or Integer#valueOf().
Long id = Long.valueOf(hexId, 16);
That said, Oracle's JDBC driver didn't support ResultSet#getGeneratedKeys() for a long time and is still somewhat troublesome with it. If you can't get that right, then you need to execute a SELECT CURRVAL(sequencename) on the same statement as you did the insert, or a new statement inside the same transaction, if it was a PreparedStatement. Basic example:
public void create(User user) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
Statement statement = null;
ResultSet generatedKeys = null;
try {
connection = daoFactory.getConnection();
preparedStatement = connection.prepareStatement(SQL_INSERT);
preparedStatement.setValue(1, user.getName());
// Set more values here.
int affectedRows = preparedStatement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
statement = connection.createStatement();
generatedKeys = statement.executeQuery(SQL_CURRVAL);
if (generatedKeys.next()) {
user.setId(generatedKeys.getLong(1));
} else {
throw new SQLException("Creating user failed, no generated key obtained.");
}
} finally {
close(generatedKeys);
close(statement);
close(preparedStatement);
close(connection);
}
}
Oh, from your code example, the following line
stmt.RETURN_GENERATED_KEYS;
is entirely superfluous. Remove it.
You can find here another example which I posted before about getting the generated keys, it uses the normal getGeneratedKeys() approach.
This question already has answers here:
How to get the insert ID in JDBC?
(14 answers)
Closed 7 years ago.
Is there some way to get a value from the last inserted row?
I am inserting a row where the PK will automatically increase, and I would like to get this PK. Only the PK is guaranteed to be unique in the table.
I am using Java with a JDBC and PostgreSQL.
With PostgreSQL you can do it via the RETURNING keyword:
PostgresSQL - RETURNING
INSERT INTO mytable( field_1, field_2,... )
VALUES ( value_1, value_2 ) RETURNING anyfield
It will return the value of "anyfield". "anyfield" may be a sequence or not.
To use it with JDBC, do:
ResultSet rs = statement.executeQuery("INSERT ... RETURNING ID");
rs.next();
rs.getInt(1);
See the API docs for java.sql.Statement.
Basically, when you call executeUpdate() or executeQuery(), use the Statement.RETURN_GENERATED_KEYS constant. You can then call getGeneratedKeys to get the auto-generated keys of all rows created by that execution. (Assuming your JDBC driver provides it.)
It goes something along the lines of this:
Statement stmt = conn.createStatement();
stmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet keyset = stmt.getGeneratedKeys();
If you're using JDBC 3.0, then you can get the value of the PK as soon as you inserted it.
Here's an article that talks about how : https://www.ibm.com/developerworks/java/library/j-jdbcnew/
Statement stmt = conn.createStatement();
// Obtain the generated key that results from the query.
stmt.executeUpdate("INSERT INTO authors " +
"(first_name, last_name) " +
"VALUES ('George', 'Orwell')",
Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
if ( rs.next() ) {
// Retrieve the auto generated key(s).
int key = rs.getInt(1);
}
Since PostgreSQL JDBC driver version 8.4-701 the PreparedStatement#getGeneratedKeys() is finally fully functional. We use it here almost one year in production to our full satisfaction.
In "plain JDBC" the PreparedStatement needs to be created as follows to make it to return the keys:
statement = connection.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
You can download the current JDBC driver version here (which is at the moment still 8.4-701).
The sequences in postgresql are transaction safe. So you can use the
currval(sequence)
Quote:
currval
Return the value most recently obtained by nextval for this sequence
in the current session. (An error is
reported if nextval has never been
called for this sequence in this
session.) Notice that because this is
returning a session-local value, it
gives a predictable answer even if
other sessions are executing nextval
meanwhile.
Here is how I solved it, based on the answers here:
Connection conn = ConnectToDB(); //ConnectToDB establishes a connection to the database.
String sql = "INSERT INTO \"TableName\"" +
"(\"Column1\", \"Column2\",\"Column3\",\"Column4\")" +
"VALUES ('value1',value2, 'value3', 'value4') RETURNING
\"TableName\".\"TableId\"";
PreparedStatement prpState = conn.prepareStatement(sql);
ResultSet rs = prpState.executeQuery();
if(rs.next()){
System.out.println(rs.getInt(1));
}
If you are using Statement, go for the following
//MY_NUMBER is the column name in the database
String generatedColumns[] = {"MY_NUMBER"};
Statement stmt = conn.createStatement();
//String sql holds the insert query
stmt.executeUpdate(sql, generatedColumns);
ResultSet rs = stmt.getGeneratedKeys();
// The generated id
if(rs.next())
long key = rs.getLong(1);
If you are using PreparedStatement, go for the following
String generatedColumns[] = {"MY_NUMBER"};
PreparedStatement pstmt = conn.prepareStatement(sql,generatedColumns);
pstmt.setString(1, "qwerty");
pstmt.execute();
ResultSet rs = pstmt.getGeneratedKeys();
if(rs.next())
long key = rs.getLong(1);
Use sequences in postgres for id columns:
INSERT mytable(myid) VALUES (nextval('MySequence'));
SELECT currval('MySequence');
currval will return the current value of the sequence in the same session.
(In MS SQL, you would use ##identity or SCOPE_IDENTITY())
PreparedStatement stmt = getConnection(PROJECTDB + 2)
.prepareStatement("INSERT INTO fonts (font_size) VALUES(?) RETURNING fonts.*");
stmt.setString(1, "986");
ResultSet res = stmt.executeQuery();
while (res.next()) {
System.out.println("Generated key: " + res.getLong(1));
System.out.println("Generated key: " + res.getInt(2));
System.out.println("Generated key: " + res.getInt(3));
}
stmt.close();
Don't use SELECT currval('MySequence') - the value gets incremented on inserts that fail.
For MyBatis 3.0.4 with Annotations and Postgresql driver 9.0-801.jdbc4 you define an interface method in your Mapper like
public interface ObjectiveMapper {
#Select("insert into objectives" +
" (code,title,description) values" +
" (#{code}, #{title}, #{description}) returning id")
int insert(Objective anObjective);
Note that #Select is used instead of #Insert.
for example:
Connection conn = null;
PreparedStatement sth = null;
ResultSet rs =null;
try {
conn = delegate.getConnection();
sth = conn.prepareStatement(INSERT_SQL);
sth.setString(1, pais.getNombre());
sth.executeUpdate();
rs=sth.getGeneratedKeys();
if(rs.next()){
Integer id = (Integer) rs.getInt(1);
pais.setId(id);
}
}
with ,Statement.RETURN_GENERATED_KEYS);" no found.
Use that simple code:
// Do your insert code
myDataBase.execSQL("INSERT INTO TABLE_NAME (FIELD_NAME1,FIELD_NAME2,...)VALUES (VALUE1,VALUE2,...)");
// Use the sqlite function "last_insert_rowid"
Cursor last_id_inserted = yourBD.rawQuery("SELECT last_insert_rowid()", null);
// Retrieve data from cursor.
last_id_inserted.moveToFirst(); // Don't forget that!
ultimo_id = last_id_inserted.getLong(0); // For Java, the result is returned on Long type (64)
If you are in a transaction you can use SELECT lastval() after an insert to get the last generated id.