java - 在 Java 中从 Postgres 加载非物化数组

标签 java arrays postgresql jdbc

设置: 我正在使用 Java 连接到 Postgres 数据库,并尝试加载 pg_stats.histogram_bounds 统计信息,它是 Postgres 中的一个数组。我可以使用 Array histogramBounds = rs.getArray("histogram_bounds"); 将该字段提取为 sql.Array 对象。该对象可以使用 toString() 打印,但我无法以其他方式访问任何数据(例如调用 histogramBounds.getArray()getBaseType 等)都会生成 PSQLException: No results were returned by the query..

documentation ,以及各种教程和 SE 问题表明这应该是有效的。

显然sql.Array对象并不直接保存数组数据,而是指向服务器上的数组数据。从我的实验中,我得到了以下 MWE,它显示了存储在 Postgres 表中的数组值与某种短暂或非物化的数组值之间的差异(正如我怀疑 pg_stats 可能是,作为一个查看其他内部表)。

MWE: 我有两个查询,一个查询从表中选择数据并起作用,另一个查询直接从查询中选择数据,但不起作用。我在文档中看不到它们不能同时工作的任何原因,并且我希望第二个版本能够工作以获取 Java 数组 [1, 2, 3]。 令人困惑的是,在第二种情况下,toString 仍然可以正确显示数据,因此它必须在某个时刻成功加载。

import java.sql.Array;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class PostgresStatsExperiments {
    public static void main(String[] args) throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost/tmp", "admin", "admin");
        Statement stmt = conn.createStatement();

        ResultSet rs = stmt.executeQuery("SELECT name, my_data from array_test;"); // This one works
        //ResultSet rs = stmt.executeQuery("SELECT '{1, 2, 3}' AS my_data;"); // This one does not work.

        while (rs.next()) {
            Array myData = rs.getArray("my_data");
            System.out.println(myData);
            System.out.println(myData.getArray()); // PSQLException here in the second case
        }

        stmt.close();
        rs.close();
        conn.close();
    }
}

表格array_test看起来像这样:

create table array_test ( name varchar, my_data integer ARRAY[3] );
insert into array_test values ('Alice', '{1, 2, 3}');
insert into array_test values ('Bob', '{4, 5, 6}');

在第二种情况下,我得到以下输出:

{1, 2, 3}
Exception in thread "main" org.postgresql.util.PSQLException: No results were returned by the query.
    at org.postgresql.jdbc2.TypeInfoCache.getPGArrayElement(TypeInfoCache.java:425)
    at org.postgresql.jdbc2.AbstractJdbc2Array.buildArray(AbstractJdbc2Array.java:540)
    at org.postgresql.jdbc2.AbstractJdbc2Array.getArrayImpl(AbstractJdbc2Array.java:171)
    at org.postgresql.jdbc2.AbstractJdbc2Array.getArray(AbstractJdbc2Array.java:128)
    at tmp.PostgresStatsExperiments.main(PostgresStatsExperiments.java:21)

我使用的是Maven中的postgresql-9.3-1102-jdbc41.jar,最新的42.2.4.jre7也有同样的问题。

最佳答案

在查询 SELECT '{1, 2, 3}' AS my_data 中,my_data不是任何数组。它是一个看起来像数组的字符串 - 但单引号表示 text(或 varchar)值。

并且由于列的数据类型不是数组,因此调用 getArray() 会引发异常。

如果你想要一个数组,则需要将文本值转换为数组:

SELECT '{1, 2, 3}'::int[] AS my_data;

或者更好:使用显式数组构造函数:

SELECT array[1, 2, 3] AS my_data;

pg_stats.histogram_bounds 定义为 anyarray - 它不是类型化数组,因为它每列包含不同的数据类型(这意味着在每一行中,因为该表包含每个表列一行)。

显然 JDBC 驱动程序无法正确使用 anyarray

要处理 Java 代码中的值,我认为最简单的方法是将其转换为字符串,然后可以将其转换回文本数组(因为字符串表示形式是正确的)。

因此,如果您使用以下查询:

select schemaname, tablename, attname, histogram_bounds::text::text[] as histogram_bounds, ..
from pg_stats
where ...

您应该能够检索 histogram_bounds 列的内容(但您获取的所有内容都是字符串,而不是与列的数据类型匹配的数据类型)。

关于java - 在 Java 中从 Postgres 加载非物化数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52189147/

相关文章:

java - 如何在一行中获取由 ArrayList<Object> 的 .toString() 调用组成的 String[]

java - Jpanel 和图形错误

java - Spring Boot 基于角色的身份验证

java - 我的随机数组给了我相同的答案,而它应该是不同的

javascript - 只使用一次数组元素

node.js - Node postgres插入语法错误

postgresql - 选择 Postgres 数据库中没有任何空值的记录

sql - 给定年份创建的所有表的打印大小

java - 如何优化存钱 jar 中的硬币数量?

java - JPA和JTA模式下的事务(开始和提交)