I use triggers to set PK column values of all tables so i do not do any operation about IDs in java but i need the ID after insert.
How can i get the ID?
stat.execute("INSERT INTO TPROJECT_PROCESS_GROUP(NPROJECT_ID,VDESCRIPTION) " +
"VALUES(" +
"'" + projectID + "'," +
"'" + description + "'" +
"");
Edit: Hi again I read the question, now I get an exception like 'unsupported operation'(i translated from my native language the exact english form might be different). i guess this is about oracle's support for GetGeneratedKeys? Do you know anything about this?
Solution: As mentioned in a book about callablestatements This statement can be used to execute stored procedures and functions. Unlike the PreparedStatement, most databases do not perform any preparation for the call,because it is such a simple command. The CallableStatement instances can be used toreturn the object that the stored procedure—or function, to be more exact—returned.
OracleConnection conn = null;
//OraclePreparedStatement pstat = null;
OracleCallableStatement cstat = null;
String sql = "BEGIN INSERT INTO TPROJECT P (VPROJECT_TITLE,VPROJECT_DESC) VALUES(?,?) RETURNING P.NPROJECT_ID INTO ?; END;";
try {
conn = ConnectionUtility.GetConnection();
cstat = (OracleCallableStatement)conn.prepareCall(sql);
cstat.setString(1, title);
cstat.setString(2, description);
cstat.registerOutParameter(3, OracleTypes.NUMBER);
cstat.execute();
int returnedID = cstat.getInt(3);
// System.out.println(returnedID);
conn.close();
return returnedID;
This example is how you would do it in PostgreSQL. Hopefully you can do something similar in Oracle.
This is how you get the id after INSERT INTO for auto-generated keys like serial . Important here is to provide RETURN_GENERATED_KEYS in the prepareStatement() call.
Resultset result;
PreparedStatement prep;
String query = "INSERT INTO myRel (data) VALUES (?)";
prep = db.prepareStatement(query ,Statement.RETURN_GENERATED_KEYS);
result = prep.getGeneratedKeys();
if(result.next() && result != null){
System.out.println("Key: " + result.getInt(1));
} else {
System.out.println("No, Nop nada");
}
Hope that helps someone :)
Related
I am trying to use the preparedStatement Batch but I am having a problem.
The following code does not give me errors, but it inserts in the table only last key of the map and I do not know why.
It will be surely a very stupid error, but this is the first time I use the addBatch() method..
Class.forName("com.mysql.jdbc.Driver");
this.connect = DriverManager.getConnection("jdbc:mysql://localhost/" + this.database + "?user=" + this.user + "&password=" + this.password);
String s;
for (String key : this.map.keySet())
{
s = ("insert into " + this.database + ".user (nickname) values (?)");
this.preparedStatement = this.connect.prepareStatement(s);
this.preparedStatement.setString(1, key);
this.preparedStatement.addBatch();
}
this.preparedStatement.executeBatch();
Thanks in advance!
Prepare your Statement and query outside of the loop:
s = ("insert into " + this.database + ".user (nickname) values (?)");
this.preparedStatement = this.connect.prepareStatement(s);
for (String key : this.map.keySet())
{
this.preparedStatement.setString(1, key);
this.preparedStatement.addBatch();
}
this.preparedStatement.executeBatch();
You are using the addBatch() method wrong. In your code you are doing the prepareStatement in each iteration of for loop, and this replaces the prepared query each time.
You should only be calling prepareStatement once per batch. You should place the prepared statement before the loop (only one call)
Background
I am trying to set the contents of an ArrayList into an IN clause in a Db2 SQL statement. I am using the PreparedStatement to build my query. This is our coding standard.
What I tried #1
I researched a couple ways to achieve this. I first tried using the setArray() as show in this question: How to use an arraylist as a prepared statement parameter The result was I was getting a error of Err com.ibm.db2.jcc.am.SqlFeatureNotSupportedException: [jcc][t4][10344][11773][3.65.110] Data type ARRAY is not supported on the target server. ERRORCODE=-4450, SQLSTATE=0A502 After this roadblock, I moved on to #2
What I tried #2
I then tried using the Apache Commons StringUtils to convert the ArrayList into a comma separated String like I needed for my IN clause. The result is that this did exactly what I needed, I have a single String with all my results separated by a comma.
The problem:
The setString() method is adding single quotes to the beginning and end of my String. I have used this many times, and it has never done this. Does anyone know if there is a way around this, or an alternative using the PreparedStatement?? If I use String concatenation my query works.
Code (explained above):
List<String> selectedStatuses = new ArrayList<String>(); //Used to store contents of scoped var
//Get Contents of Checkbox which are in the form of a List
selectedStatuses = (List) viewScope.get("selectedStatuses");
String selectedStatusesString = StringUtils.join(selectedStatuses, ",");
.... WHERE ATM_DET_ATM_STAT IN (?)";
ps.setString(1, selectedStatusesString);
Log Value showing correct value of String
DEBUG: selectedStatusesString: 'OPEN','CLOSED','WOUNDED','IN PROGRESS'
Visual of incorrect result
The quotes at the beginning and end are the problem.
For an IN clause to work, you need as many markers as you have values:
String sql = "SELECT * FROM MyTable WHERE Stat IN (?,?,?,?)";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, "OPEN");
stmt.setString(2, "CLOSED");
stmt.setString(3, "WOUNDED");
stmt.setString(4, "IN PROGRESS");
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Since you have a dynamic list of values, you need to do this:
List<String> stats = Arrays.asList("OPEN", "CLOSED", "WOUNDED", "IN PROGRESS");
String markers = StringUtils.repeat(",?", stats.size()).substring(1);
String sql = "SELECT * FROM MyTable WHERE Stat IN (" + markers + ")";
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
for (int i = 0; i < stats.size(); i++)
stmt.setString(i + 1, stats.get(i));
try (ResultSet rs = stmt.executeQuery()) {
// use rs here
}
}
Starting with Java 11, StringUtils is no longer needed:
String markers = ",?".repeat(stats.size()).substring(1);
Use two apostrophes '' to get a single apostrophe on DB2, according to the DB2 Survival Guide. Then call .setString().
To anyone else experiencing the issue with single quotes, I had to modify my function so that it doesn't use ? to set the value; instead, I just treat the entire query as a string:
public static void runQuery(String tableName, String columnName, int value, String whereName, String whereValue) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE " + tableName + " SET " + columnName + " = " + value + " WHERE " + whereName + " = " + "'" + whereValue + "'")) {
ps.executeUpdate();
}
} catch (SQLException ex) {
ex.printStackTrace();
}
}
Hope this helps
So I created the following function to write to a database:
public static void updateBuyer(String ID, String name, Location latlong) {
float lat = latlong.latitude;
float lon = latlong.longitude;
try {
// new com.mysql.jdbc.Driver();
Class.forName("com.mysql.jdbc.Driver").newInstance();
// conn =
// DriverManager.getConnection("jdbc:mysql://localhost:3306/testdatabase?user=testuser&password=testpassword");
conn = DriverManager.getConnection(connectionUrl, connectionUser,
connectionPassword);
stmt = conn.createStatement();
String sql = "UPDATE Buyer " + "SET latitude ="
+ Float.toString(lat) + " WHERE idBuyer in (" + ID + ")";
String sql2 = "UPDATE Buyer " + "SET longitude ="
+ Float.toString(lon) + " WHERE idBuyer in (" + ID + ")";
String sql3 = "UPDATE Buyer " + "SET Name =" + name
+ " WHERE idBuyer in (" + ID + ")";
stmt.executeUpdate(sql);
stmt.executeUpdate(sql2);
stmt.executeUpdate(sql3);
conn.close();
} catch (Exception e) {
System.err.println(e);
}
}
Lets say I passed the following parameters:
(12,craigs,location object)
Now when I run the function I get the following error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'craigs' in 'field list'
12 is the ID i retrieved from the databases earlier,
craigs is the random name I am trying to insert, and
location object is just a set of coordinates (lat,long)
Which leads me to think that it is looking for a field called "craigs" in the table for some reason, but why would it do that?
The problem is that you've got SQL like this:
UDPATE Buyer SET Name = craigs WHERE idBuer in (Whatever)
That's trying to copy the value from a column named "craigs".
Now you could just add apostrophes - but don't. Instead, use parameterized SQL with a prepared statement. That way you'll avoid SQL injection attacks, your code will be simpler, and you'll avoid unnecessary string conversions which can cause problems, particularly with date values.
Additionally, you only need a single statement, which can update all three columns:
String sql = "UPDATE Buyer SET Name=?, latitude=?, longitude=? WHERE idBuyer=?";
try (PreparedStatement statement = conn.prepareStatement(sql)) {
statement.setString(1, name);
statement.setFloat(2, lat);
statement.setFloat(3, lon);
statement.setString(4, ID);
statement.executeUpdate();
}
(Note that I've assumed you're actually only trying to update a single buyer - it's not clear why you were using IN at all. Also note that I'm using a try-with-resources statement, which will automatically close the statement afterwards.)
Additionally, I would *strongly *advise you to avoid just catching Exception. Catch SQLException if you must - but you'd actually probably be better letting it just propagate up the call stack.
This is the code block in question:
String sq = "INSERT INTO survey (session_id, character_id, timestamp) VALUES (?,?,?)";
PreparedStatement sadd = conn.prepareStatement(sq, PreparedStatement.RETURN_GENERATED_KEYS);
sadd.setLong(1, sessionId);
sadd.setLong(2, character_id);
sadd.setString(3, dateTime);
int affectedrows = sadd.executeUpdate();
//get the ID
long resultId = 0;
ResultSet key = sadd.getGeneratedKeys();
if (key.next()) {
resultId = key.getLong(1);
}
This query worked fine without the PreparedStatement.RETURN_GENERATED_KEYS option, but when I add it suddenly executeUpdate() throws an exception:
com.microsoft.sqlserver.jdbc.SQLServerException: A result set was generated for update.
If I take the PreparedStatement.RETURN_GENERATED_KEYS out, it works again fine. Out of frustration, I changed executeUpdate() to executeQuery() just to see if I could get the key back and got an exception that it can't get keys because the statement must be executed first.
How can I get the generated key? I am using SQL Server 2008 and the latest JDBC driver.
Looks like a driver bug to me.
You should try a newer 4.0 driver from here -> http://www.microsoft.com/download/en/details.aspx?id=11774
If that does not work, one work around would be to create an 'insert' stored procedure and return the generated id as a stored procedure output parameter.
Looks like a bug. Could you give the uglier alternative a try?
String dateTimeS = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm").format(dateTime);
String sq = "INSERT INTO survey (session_id, character_id, timestamp) "
+ "VALUES (" + sessionId + ", " + character_id + ", '" + dateTimeS + "')";
Statement sadd = conn.createStatement();
int affectedrows = sadd.executeUpdate(sq, Statement.RETURN_GENERATED_KEYS);
I'm having the same issue with the 4.0 & 4.1 JDBC drivers. After a while an insert on a autonumber table would give a "A result set was generated for update." at random. I use connection pooling and somehow the driver can get into a state where executeUpdate in combination with Statement.RETURN_GENERATED_KEYS doesn't work anymore. I found out that in this state an executeQuery does the trick, but in the initial state executeQuery does not work. This lead me to the following workaround:
PreparedStatement psInsert = connection.prepareStatement("INSERT INTO XYZ (A,B,C) VALUES(?,?,?)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = null;
try {
psInsert.setString(1, "A");
psInsert.setString(2, "B");
psInsert.setString(3, "C");
Savepoint savePoint = connection.setSavepoint();
try {
psInsert.executeUpdate();
rs = psInsert.getGeneratedKeys();
} catch (SQLServerException sqe)
{
if (!sqe.getMessage().equals("A result set was generated for update."))
throw sqe;
connection.rollback(savePoint);
rs = psInsert.executeQuery();
}
rs.next();
idField = rs.getInt(1);
} finally {
if(rs != null)
rs.close();
psInsert.close();
}
I am attempting to pull results from an Oracle database. I have written a query that is correct, and produces accurate results when issued manually in sqlplus. Furthermore, the code works as expected when when the query matches only one row (In other words, when the ResultSet has only one row, everything works). However, when more than one row match the query, the ResultSet returned by the Oracle JDBC is empty.
public Component[] getAllComponents(int typeId, int osId) throws SQLException
{
String query= "SELECT c.component_id, c.component_name, c.component_version, c.type_id, c.post_download_instructions, "
+ "o.os_id, o.os_name, o.description AS os_description, "
+ "i.file_location, i.release_date, i.patch_number, i.file_id, "
+ "i.description AS i_description "
+ "FROM components c, installation_files i, operating_systems o "
+ "WHERE c.type_id = ? "
+ "AND i.os_id = ? "
+ "AND c.component_id = i.component_id "
+ "AND i.os_id = o.os_id";
ResultSet results = null;
PreparedStatement stmt = null;
ArrayList<Component> found = new ArrayList<Component>();
try {
stmt = dbConn.prepareStatement(query); //dbConn is member variable
stmt.setInt(1, typeId);
stmt.setInt(2, osId);
results = stmt.executeQuery();
while(results.next()){
//Some logic
}
} finally {
if(results != null) results.close();
if(stmt != null) stmt.close();
dbConn.close();
}
//More Code
//etc. etc.
Inspecting the ResultSet shows that calling ResultSet.next() never produces true when the fetched results should contain more than one row. However, issuing the query manually does produce results, and when only one row is returned, everything works fine. Does anyone know what's going on? I'm using Oracle's ojdbc6.jar.
Thanks!
Before that query you can check if there really are some components with COUNT(*) instead of all fields. Then run your query only if COUNT(*) is one or more.