我对 postgresql 很陌生,正在努力使用数组
我有一张桌子
bookIds
,看起来像这样
书号 | 位置_id | 签出版本 |
---|---|---|
12 | 1 | 10 |
15 | 1 | 12 |
从 Java 代码中,我将签出版本、位置 id 和书籍 id 的数组传递给查询,并且查询需要:
UPDATE bookIds SET checked_out_version = (values in the array?)
WHERE location_id = ANY (:locationIDS)
AND book_id = ANY (:bookIDS)
我不断收到错误,Postgres 不支持使用
SET
语句中的 UPDATE
子句更新带有数组的 col。
我也尝试过循环,但显然,它将签出的版本设置为数组中的最新版本。
示例:
如果我传递以下数组
bookIds [12,15]
位置IDS [1,1]
检查版本 [11, 20]
表格需要更新为如下所示
书号 | 位置_id | 签出版本 |
---|---|---|
12 | 1 | 11 |
15 | 1 | 20 |
这是我尝试过的循环:
DO $$
DECLARE
i integer;
BEGIN
FOREACH i IN ARRAY :checkedOutVersions::integer[] LOOP
RAISE NOTICE 'Value: %', i;
UPDATE bookIds SET checked_out_version = i
WHERE location_id = ANY (:locationIDs::bigint[])
AND book_id = ANY (:bookIDs::integer[]);
END LOOP;
END $$;
如何正确执行此操作?
您不需要 PL/pgSQL 块中的循环,因此也不需要
DO
命令。
UPDATE
语句并以 unnest()
作为设置返回函数锁步解除数组的嵌套:
UPDATE bookids b
SET checked_out_version = t.ver
FROM unnest('{12,15}'::int[] -- :bookIDs
, '{1,1}'::bigint[] -- :locationIDs
, '{11,20}'::int[] -- :checkedOutVersions
) AS t(book_id, loc_id, ver)
WHERE b.location_id = t.loc_id
AND b.book_id = t.book_id;
(带有
location_id = ANY (:locationIDs::bigint[])
等的想法将导致组合数组中元素的笛卡尔积。昂贵的废话。)
参见:
另请注意 Postgres 数组文字的语法:
也许作为准备好的声明?准备:
PREPARE upd1(int[], bigint[], int[]) AS
UPDATE bookids b
SET checked_out_version = t.ver
FROM unnest($1, $2, $3) AS t(book_id, loc_id, ver)
WHERE b.location_id = t.loc_id
AND b.book_id = t.book_id;
执行:
EXECUTE upd1('{12,15}', '{1,1}', '{11,20}');
调用中不需要显式类型转换,因为参数类型已在
PREPARE
中声明。还隐式安全地防止 SQL 注入(这可能是简单插值/串联的问题)。对 JDBC 了解不多,但每种主要编程语言都有处理预准备语句的库。
旁白:使用合法的、小写的、不带引号的标识符,让您的 Postgres 生活更轻松。参见: