我正在使用带有单个查询的PreparedStatement插入多行:
String query = "insert into MyTable (a,b,c) values (?,?,?),(?,?,?),(?,?,?),(?,?,?)"; // insert 4 rows in a single query
PreparedStatement stmt = connection.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
// .. here: loop to set all 4 x 3 values in my prepared statement
我想获取MSSQL DB生成的ID。我不确定使用哪种execute
。
execute()
方法未返回预期的ResultSet
:
boolean thingy = stmt.execute();
System.out.println("execute returned ", thingy); // false: meaning no result set
ResultSet result = stmt.getResultSet(); // result is null
executeUpdate()
方法只返回一个ResultSet
:
int rowCount = stmt.executeUpdate();
System.out.println(rowCount + " rows updated"); // 4 rows updated
ResultSet result = stmt.getGeneratedKeys();
// there's only one result:
result.next(); // true
int ID1 = result.getInt(1); // good
result.next(); // false, no more rows
是否可以通过单个INSERT获取生成的ID?出于性能原因,我不想发送多个INSERT查询。
DB:MS SQL Server 11(2012)
URL:jdbc:jtds:sqlserver:// ...
驱动程序:net.sourceforge.jtds.jdbc.Driver jtds版本1.3.1
答案 0 :(得分:2)
对于SQL Server 2008及更高版本,向INSERT语句添加OUTPUT clause似乎可以解决问题:
try (Statement st = conn.createStatement()) {
// TEST ENVIRONMENT: in a real application, this would be our permanent table
st.execute("CREATE TABLE #tmp (id INT IDENTITY PRIMARY KEY, txtcol NVARCHAR(50))");
st.execute("INSERT INTO #tmp (txtcol) VALUES (N'existing data')");
st.execute("INSERT INTO #tmp (txtcol) VALUES (N'more existing data')");
}
StringBuilder sb = new StringBuilder();
sb.append("INSERT INTO #tmp (txtcol) ");
sb.append(" OUTPUT INSERTED.id ");
sb.append(" VALUES (?), (?), (?) ");
try (PreparedStatement ps = conn.prepareStatement(sb.toString())) {
ps.setString(1, "foo");
ps.setString(2, "bar");
ps.setString(3, "baz");
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt(1));
}
}
}
产生
3
4
5
答案 1 :(得分:1)
在撰写本回答时,jTDS和mssql-jdbc都不支持使用Statement.RETURN_GENERATED_KEYS
从带有TVC的INSERT语句(表值构造函数)或使用{{1}返回多个生成的密钥} executeBatch
。但是,以下代码适用于两个驱动程序(在撰写本文时使用jTDS 1.3.1和the dev branch of mssql-jdbc进行测试):
PreparedStatement
产生
try (Statement st = conn.createStatement()) {
// TEST ENVIRONMENT: in a real application, this would be our permanent table
st.execute("CREATE TABLE #tmp (id INT IDENTITY PRIMARY KEY, txtcol NVARCHAR(50))");
st.execute("INSERT INTO #tmp (txtcol) VALUES (N'existing data')");
st.execute("INSERT INTO #tmp (txtcol) VALUES (N'more existing data')");
}
StringBuilder sb = new StringBuilder();
sb.append("SET NOCOUNT ON; ");
sb.append("DECLARE @seq INT, @txt NVARCHAR(50), @id INT; ");
sb.append("DECLARE @newIds TABLE (seq INT, id INT); ");
sb.append("DECLARE @toInsert TABLE (seq INT IDENTITY PRIMARY KEY, txt NVARCHAR(50)); ");
sb.append("");
sb.append("INSERT INTO @toInsert (txt) VALUES (?), (?), (?); ");
sb.append("");
sb.append("DECLARE crsr CURSOR FOR SELECT seq, txt FROM @toInsert ORDER BY seq; ");
sb.append("OPEN crsr; ");
sb.append("FETCH NEXT FROM crsr INTO @seq, @txt; ");
sb.append("WHILE @@FETCH_STATUS = 0 ");
sb.append("BEGIN ");
sb.append(" INSERT INTO #tmp (txtcol) VALUES (@txt); ");
sb.append(" SELECT @id = SCOPE_IDENTITY(); ");
sb.append(" INSERT INTO @newIds (seq, id) VALUES (@seq, @id); ");
sb.append(" FETCH NEXT FROM crsr INTO @seq, @txt; ");
sb.append("END ");
sb.append("SELECT id FROM @newIds ORDER BY seq; ");
try (PreparedStatement ps = conn.prepareStatement(sb.toString())) {
ps.setString(1, "foo");
ps.setString(2, "bar");
ps.setString(3, "baz");
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt(1));
}
}
}