如何将数组参数传递给 Postgres 查询?

问题描述 投票:0回答:1

我对 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 $$;

如何正确执行此操作?

sql postgresql prepared-statement spring-jdbc
1个回答
0
投票

您不需要 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 生活更轻松。参见:

© www.soinside.com 2019 - 2024. All rights reserved.