2010-08-23 24 views
18

¿Cuál es el equivalente PLSQL (Oracle) de este fragmento de servidor SQL?PLSQL JDBC: ¿Cómo obtener la última fila de identificación?

BEGIN TRAN 
INSERT INTO mytable(content) VALUES ("test") -- assume there's an ID column that is autoincrement 
SELECT @@IDENTITY 
COMMIT TRAN 

En C#, puede llamar myCommand.ExecuteScalar() para recuperar el ID de la nueva fila.

¿Cómo puedo insertar una nueva fila en Oracle y hacer que JDBC obtenga una copia de la nueva identificación?

EDIT: BalusC proporciona un muy buen punto de partida. Por algún motivo, a JDBC no le gusta el enlace de los parámetros nombrados. Esto proporciona SQLException "Parámetros registrados o configurados incorrectamente". ¿Por qué está pasando esto?

 OracleConnection conn = getAppConnection(); 
     String q = "BEGIN INSERT INTO tb (id) values (claim_seq.nextval) returning id into :newId; end;" ; 
     CallableStatement cs = (OracleCallableStatement) conn.prepareCall(q); 
     cs.registerOutParameter("newId", OracleTypes.NUMBER); 
     cs.execute(); 
     int newId = cs.getInt("newId"); 
+0

Seleccione el máximo del campo id + 1? – Aren

+4

@Aren - 'max (n) + 1' no escala y no funciona en un entorno multiusuario. – APC

Respuesta

33

Normalmente que usaría para este Statement#getGeneratedKeys() (véase también this answer para un ejemplo), pero esto es lo más lejos (todavía) no compatible con el controlador JDBC de Oracle.

Su mejor apuesta es ya sea hacer uso de CallableStatement con un RETURNING cláusula:

String sql = "BEGIN INSERT INTO mytable(id, content) VALUES (seq_mytable.NEXTVAL(), ?) RETURNING id INTO ?; END;"; 

Connection connection = null; 
CallableStatement statement = null; 

try { 
    connection = database.getConnection(); 
    statement = connection.prepareCall(sql); 
    statement.setString(1, "test"); 
    statement.registerOutParameter(2, Types.NUMERIC); 
    statement.execute(); 
    int id = statement.getInt(2); 
    // ... 

O fuego SELECT sequencename.CURRVAL después INSERT en la misma transacción:

String sql_insert = "INSERT INTO mytable(content) VALUES (?)"; 
String sql_currval = "SELECT seq_mytable.CURRVAL FROM dual"; 

Connection connection = null; 
PreparedStatement statement = null; 
Statement currvalStatement = null; 
ResultSet currvalResultSet = null; 

try { 
    connection = database.getConnection(); 
    connection.setAutoCommit(false); 
    statement = connection.prepareStatement(sql_insert); 
    statement.setString(1, "test"); 
    statement.executeUpdate(); 
    currvalStatement = connection.createStatement(); 
    currvalResultSet = currvalStatement.executeQuery(sql_currval); 
    if (currvalResultSet.next()) { 
     int id = currvalResultSet.getInt(1); 
    } 
    connection.commit(); 
    // ... 
+0

¿Quiere decir "SELECT seq_mytable.CURRVAL from dual" en lugar de "SELECT CURRVAL (seq_mytable)"? –

+0

@Patrick: Oh, diablo, tenía la sintaxis PostgreSQL SQL en mente, actualizaré (anteriormente, PostgreSQL solía tener el mismo problema de no admitir ['Statement # getGeneratedKeys()'] (http://stackoverflow.com/ questions/1915166/jdbc-how-can-we-get-inserted-record-id-in-java/1915197 # 1915197) por lo que la misma "solución" fue necesaria, pero desde hace aproximadamente un año finalmente arreglaron su controlador JDBC para apoyarlo). – BalusC

+0

Hola BalusC, gracias por la ayuda. ¿Puedes echar un vistazo a mi edición para ver si puedes resolver ese otro misterio? – Haoest

8

Puede utilizar la cláusula returning de Oracle.

insert into mytable(content) values ('test') returning your_id into :var; 

Consulte this link para obtener un código de muestra. Necesita Oracle 10g o posterior, y una nueva versión del controlador JDBC.

1

Se puede utilizar getGeneratedKeys(), al seleccionar explícitamente el campo clave. Aquí hay un fragmento:

// change the string to your connection string 
    Connection connection = DriverManager.getConnection("connection string"); 

    // assume that the field "id" is PK, and PK-trigger exists 
    String sql = "insert into my_table(id) values (default)"; 
    // you can select key field by field index 
    int[] colIdxes = { 1 }; 
    // or by field name 
    String[] colNames = { "id" }; 

    // Java 1.7 syntax; try-finally for older versions 
    try (PreparedStatement preparedStatement = connection.prepareStatement(sql, colNames)) 
    { 
     // note: oracle JDBC driver do not support auto-generated key feature with batch update 
     //   // insert 5 rows 
     //   for (int i = 0; i < 5; i++) 
     //   { 
     //    preparedStatement.addBatch(); 
     //   } 
     //   
     //   int[] batch = preparedStatement.executeBatch(); 
     preparedStatement.executeUpdate(); 

     // get generated keys 
     try (ResultSet resultSet = preparedStatement.getGeneratedKeys()) 
     { 
      while (resultSet.next()) 
      { 
       // assume that the key's type is BIGINT 
       long id = resultSet.getLong(1); 
       assertTrue(id != 0); 

       System.out.println(id); 
      } 
     } 
    } 

se refieren a detalles: http://docs.oracle.com/cd/E16655_01/java.121/e17657/jdbcvers.htm#CHDEGDHJ

+1

Esto funciona siempre que la instrucción de inserción tenga hasta 7 parámetros, cuando hay más de 7 parámetros se lanza una excepción ArrayIndexOutofBound. Parece una falla con el controlador Oracle jdbc. # Oracle_11g_R2. La respuesta de BalusC es mejor por esta razón. –

Cuestiones relacionadas