2010-08-23 17 views
18

什麼是PLSQL(Oracle)等同於此SQL服務器片段?PLSQL JDBC:如何獲取最後一行ID?

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

在C#中,您可以調用myCommand.ExecuteScalar()來檢索新行的ID。

如何在Oracle中插入新行,並讓JDBC獲得新ID的副本?

編輯: BalusC提供了一個非常好的起點。出於某種原因,JDBC不喜歡命名參數綁定。這會給出「錯誤地設置或註冊參數」SQLException。這是爲什麼發生?

 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

選擇id字段+ 1的最大? – Aren 2010-08-23 22:48:16

+4

@Aren - 'max(n)+ 1'不能縮放,並且在多用戶環境下不起作用。 – APC 2010-08-24 12:37:46

回答

33

通常你會使用Statement#getGeneratedKeys()這個(見this answer的例子),但是這是遠(還)不是由Oracle JDBC驅動程序的支持。

你最好的賭注是要麼化妝用的CallableStatementRETURNING條款:

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

或者SELECT sequencename.CURRVALINSERT後,在同一個事務:

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

你的意思是「從雙重選擇seq_mytable.CURRVAL」而不是「SELECT CURRVAL(seq_mytable)」? – 2010-08-23 23:17:01

+0

@Patrick:呵呵,我有PostgreSQL的SQL語法,我會更新(以前,PostgreSQL曾經有同樣的問題,不支持['Statement#getGeneratedKeys()'](http://stackoverflow.com/問題/ 1915166/jdbc-how-can-we-get-inserted-record-id-in-java/1915197#1915197),因此需要使用相同的「解決方法」,但大約一年前,他們終於修復了它們的JDBC驅動程序以支持它)。 – BalusC 2010-08-23 23:22:42

+0

Hi BalusC,感謝您的幫助。你能看看我的編輯,看看你是否可以解決其他的奧祕? – Haoest 2010-08-24 01:00:29

8

您可以使用Oracle的returning子句。

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

查看this link代碼示例。您需要Oracle 10g或更高版本以及新版本的JDBC驅動程序。

1

您可以使用getGeneratedKeys(),通過顯式選擇關鍵字段。 這裏是一個片段:

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

參閱有關詳情:http://docs.oracle.com/cd/E16655_01/java.121/e17657/jdbcvers.htm#CHDEGDHJ

+1

只要插入語句有多達7個參數,當超過7個參數拋出一個ArrayIndexOutofBound異常時,這將起作用。看起來像oracle jdbc驅動程序的錯誤。 #Oracle_11g_R2。由於這個原因,BalusC的回答更好。 – 2016-08-19 22:46:08