2010-08-23 16 views
18

Jaki jest ekwiwalent PLSQL (Oracle) tego fragmentu kodu serwera SQL?PLSQL JDBC: Jak uzyskać identyfikator ostatniego rzędu?

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

W języku C#, można zadzwonić myCommand.ExecuteScalar(), aby pobrać identyfikator nowego wiersza.

Jak mogę wstawić nowy wiersz w Oracle i JDBC uzyskać kopię nowego identyfikatora?

EDYCJA: BalusC dostarczył bardzo dobry punkt wyjścia. Z jakiegoś powodu JDBC nie lubi powiązania nazwanego parametru. Daje to "Niepoprawnie ustawione lub zarejestrowane parametry" Wyjątek SQLException. Dlaczego to się dzieje?

 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

Wybierz max polu id + 1? – Aren

+4

@Aren - 'max (n) + 1' nie skaluje się i nie działa w środowisku wielu użytkowników. – APC

Odpowiedz

33

Normalnie byłoby użyć Statement#getGeneratedKeys() dla tego (patrz także this answer na przykład), ale to jest tak daleko (jeszcze) nie są obsługiwane przez sterownik JDBC Oracle.

Najprościej jest albo wykorzystują CallableStatement z RETURNING klauzuli:

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

Albo przeciwpożarowej SELECT sequencename.CURRVAL po INSERT w tej samej transakcji:

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

Masz na myśli "SELECT seq_mytable.CURRVAL z dual" zamiast "SELECT CURRVAL (seq_mytable)"? –

+0

@Patrick: Oh drat, miałem na uwadze składnię SQL PostgreSQL, zaktualizuję (wcześniej PostgreSQL miał ten sam problem z brakiem obsługi ['Statement # getGeneratedKeys()'] (http://stackoverflow.com/ pytania/1915166/jdbc-how-can-we-get-insert-record-id-in-java/1915197 # 1915197), więc to samo "obejście" było konieczne, ale od około roku temu w końcu naprawili swój sterownik JDBC poprzeć to). – BalusC

+0

Witaj BalusC, dzięki za pomoc. Czy możesz rzucić okiem na moją edycję, czy rozwiążesz tę inną zagadkę? – Haoest

8

Można użyć klauzuli Oracle o klauzuli returning.

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

Sprawdź kod this link dla próbki kodu. Potrzebujesz Oracle 10g lub nowszej wersji oraz nowej wersji sterownika JDBC.

1

Można wykorzystać getGeneratedKeys(), Wybierając wyraźnie pole klucza. Oto fragment:

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

odnoszą się do szczegółów: http://docs.oracle.com/cd/E16655_01/java.121/e17657/jdbcvers.htm#CHDEGDHJ

+1

Działa to tak długo, jak instrukcja insert ma maksymalnie 7 parametrów, gdy jest więcej niż 7 parametrów, generowany jest wyjątek ArrayIndexOutofBound. Wygląda jak błąd w sterowniku jdbc Oracle. # Oracle_11g_R2. Odpowiedź od BalusC jest lepsza z tego powodu. –

Powiązane problemy