2010-08-23 17 views
18

Qual è l'equivalente PLSQL (Oracle) di questo snippet del server SQL?JDBC PLSQL: come ottenere l'ultimo ID riga?

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

In C#, è possibile chiamare myCommand.ExecuteScalar() per recuperare l'ID della nuova riga.

Come posso inserire una nuova riga in Oracle e JDBC ottenere una copia del nuovo ID?

MODIFICA: BalusC ha fornito un ottimo punto di partenza. Per qualche motivo a JDBC non piace il binding dei parametri con nome. Questo dà "SQLException" ai parametri impostati o registrati erroneamente. Perché sta succedendo?

 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

Selezionare il massimo del campo id + 1? – Aren

+4

@Aren - 'max (n) + 1' non scala e non funziona in un ambiente multiutente. – APC

risposta

33

Normalmente Usereste Statement#getGeneratedKeys() per questo (vedi anche this answer per esempio), ma questo è quanto (ancora) non supportata dal driver Oracle JDBC.

La cosa migliore è quella di sia fanno uso di CallableStatement con una clausola RETURNING:

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 fuoco SELECT sequencename.CURRVAL dopo INSERT nella stessa transazione:

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

Intendi "SELECT seq_mytable.CURRVAL da dual" invece di "SELECT CURRVAL (seq_mytable)"? –

+0

@Patrick: Oh drat, avevo in mente la sintassi SQL PostgreSQL, aggiornerò (in precedenza, PostgreSQL aveva lo stesso problema di non supportare ['Statement # getGeneratedKeys()'] (http://stackoverflow.com/ domande/1915166/jdbc-how-can-we-get-inserted-record-id-in-java/1915197 # 1915197) in modo che fosse necessaria la stessa "soluzione", ma da circa un anno fa hanno finalmente risolto il loro driver JDBC per supportarlo). – BalusC

+0

Ciao BalusC, grazie per l'aiuto. Puoi dare un'occhiata alla mia modifica per vedere se riesci a risolvere quell'altro mistero? – Haoest

8

È possibile utilizzare la clausola Oracle returning.

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

Verificare this link per un esempio di codice. È necessario Oracle 10g o versioni successive e una nuova versione del driver JDBC.

1

È possibile utilizzare getGeneratedKeys(), Selezionando esplicitamente il campo chiave. Ecco un frammento:

// 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); 
      } 
     } 
    } 

si riferiscono per i dettagli: http://docs.oracle.com/cd/E16655_01/java.121/e17657/jdbcvers.htm#CHDEGDHJ

+1

Questo funziona fintanto che l'istruzione di inserimento ha fino a 7 parametri, quando ci sono più di 7 parametri viene lanciata un'eccezione ArrayIndexOutofBound. Sembra un errore con il driver jdbc di Oracle. # Oracle_11g_R2. La risposta di BalusC è migliore per questo motivo. –