Java:在 DB2 SQL 查询中将数组设置为参数名称时出现问题

Java: Problems while setting an array as parameter name in DB2 SQL query

DB2 驱动程序版本:4.19.66

DB2安装版本:DB2 v11.5.7.0

Java 版本: 1.8_121

我正在尝试在 DB2 SQL 查询上设置参数:

SELECT distinct object_id AS oid 
FROM myschema.package p 
INNER JOIN myschema.package_item pi ON p.machine_id = pi.machine_id 
                                    AND p.package_id = pi.package_id 
INNER JOIN main_schema.item i ON i.item_id = pi.id_articulo
WHERE p.package_status_id = 5 AND p.machine_id IN (:machineIdsParam)

我必须说 p.machine_id 是 DB2 数据库中的一个 INTEGER 字段。

我这样准备连接:

Properties properties = new Properties();         // Create Properties object
properties.put("user", config.getDbUser());       // Set user ID for connection
properties.put("password", bdPassword);           // Set password for connection
properties.put("enableNamedParameterMarkers", 1);
connection = (DB2Connection) DriverManager.getConnection(config.getDbUrl(), properties);

然后我尝试在此查询中设置参数:

DB2PreparedStatement ps = connection.getPreparedStatement(sqlString);
List<Integer> machineIds = Array.asList(new Integer[] { 1, 5, 7, 9});
Array machineIdArray = connection.createArrayOf("INTEGER", machineIds.toArray(new Integer[idInstalaciones.length]));
ps.setJccArrayAtName("machineIdsParam", machineIdArray);

但是我收到这个错误:

com.ibm.db2.jcc.am.SqlSyntaxErrorException: [jcc][1091][10417][4.19.66] Invalid data conversion: Parameter instance com.ibm.db2.jcc.am.o@36fc695d is invalid for the requested conversion. 

我找不到关于如何使用此 setJccArrayAtName() 的示例,只有我无法找到此错误原因的文档。我只是猜测它与数据类型有关,但我不知道如何使它起作用。

我认为 Db2 的任何系列都不支持带有 IN 谓词的数组..

通常需要的是单独的参数

SELECT distinct object_id AS oid 
FROM myschema.package p 
INNER JOIN myschema.package_item pi ON p.machine_id = pi.machine_id 
                                    AND p.package_id = pi.package_id 
INNER JOIN main_schema.item i ON i.item_id = pi.id_articulo
WHERE p.package_status_id = 5 AND p.machine_id IN (:machineId1 
                                                   ,:machineId2
                                                   ,:machineId3
                                                   ,:machineId4
                                                  )

这当然要求您提前知道需要多少个值,或者至少知道某个最大数量。 (您始终可以加载任何剩余参数中的最后一个值。)

另一种选择是传递分隔字符串,该字符串被分割成单独的值。像这样(假设一个逗号分隔列表)

SELECT distinct object_id AS oid 
FROM myschema.package p 
INNER JOIN myschema.package_item pi ON p.machine_id = pi.machine_id 
                                    AND p.package_id = pi.package_id 
INNER JOIN main_schema.item i ON i.item_id = pi.id_articulo
WHERE p.package_status_id = 5 AND p.machine_id IN (select int(element)
                                                   from table (systools.split(:machineIds, ' '))
                                                  )

systools.split() 可能特定于 IBM i 的 Db2,其他平台可能在不同的架构中有它。

如果不出意外,您可以编写自己的用户定义函数 (UDF) 来进行拆分。

对于 LUW 的 Db2:

... IN 
(
  SELECT TOK
  FROM XMLTABLE
  (
    'for $id in tokenize($s, ",") return <i>{string($id)}</i>' 
    PASSING CAST (:machineIdsParam AS VARCHAR (100)) AS "s"
    COLUMNS
      TOK INT PATH '.'
  )
)

您为 :machineIdsParam 参数传递了类似“1,2,3”的字符串。即:以逗号分隔的 int 值。