執行批量的 insert
INSERT INTO users (id, level)
VALUES (1, 3), (2, 1)
ON CONFLICT (id) DO UPDATE
SET level = excluded.level;
我們看到已存在行(id=1) 的 level 更新爲新的值 3, 並且插入新行。
這裏注意到我們用到一個關鍵字 excluded 用於引用 INSERT 語句中 VALUES 提供的值,相應的表名 users 用於引用表中原有的值。
基於 unnest 的 upsert 操作
前面仍然是寫作此文的意外收穫,實際上想要總結的是 unnest 關鍵字在批量操作中的作用。下面來進行演示
insert into testunnest(id, col1, col2)
values (unnest(array[1,2]), unnest(array[30,40]), unnest(array['val1', 'val2']));
換成成 unnest(array[..]) 的形式有一種行轉列的行爲。
用 unnest 加上 unsert 再執行一次插入
insert into testunnest(id, col1, col2)
values (unnest(array[2,3]), unnest(array[80,90]), unnest(array['valupdated', 'val3']))
on conflict (id) do update
set col1 = excluded.col1, col2 = excluded.col2
unnest 與 JDBC 操作
insert into users values (?, ?) on conflict.... 的 SQL 語句的單條記錄或批量操作(addBatch(), executeBatch()) 就不多說了,主要看下用 JDBC 怎麼對 unnest 進行賦值操作
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO testunnest(id, col1, col2) " +
" VALUES (unnest(?), unnest(?), unnest(?))" +
" ON CONFLICT (id) DO UPDATE" +
" SET col1 = excluded.col1, col2 = excluded.col2"
);
pstmt.setArray(1, conn.createArrayOf("int", new Integer[]{2, 3}));
pstmt.setArray(2, conn.createArrayOf(JDBCType.INTEGER.getName(), new Integer[]{80, 90}));
pstmt.setArray(3, conn.createArrayOf("varchar", new String[]{"val1", "val2"}));
int update = pstmt.executeUpdate();
System.out.println(update); //影響的記錄數是 2
點位符要用 unnest(?),設置參數時要用 setArray(), 參數用 conn.createArrayOf(type, array) 來指定。需要指明數組中的元素類型,這麼普通的 setInt(), setString() 是一個意思。
用不着轉換爲 PostgreSQL 特定的 PreparedStatement 來操作,用 JDBC 通用的 PreparedStatement 接口就能支持對數組類型的賦值