Spring JPA单查询返回两表数据及函数创建异常排查
问题解答
异常原因分析
你遇到的org.postgresql.util.PSQLException: The column index is out of range: 1, number of columns: 0异常,核心原因是自定义函数的返回结果与JDBC处理逻辑不匹配:
- 自定义函数的返回表类型定义有误,或者函数内部逻辑没有生成符合预期的结果集,导致PostgreSQL返回了空列的结果集,但你的代码尝试读取第1列数据
- 调用函数的语法错误,比如参数传递错误、函数调用格式不对,触发了空结果集返回
- 实体类与函数返回的列结构不匹配,JDBC无法映射结果,进而认为结果集无列
可行实现方案
方案1:Service层分组处理(简单易维护)
适合数据量不大的场景,逻辑清晰:
- 在
TableOneRepository中查询所有TableOne记录:List<TableOne> findAll(); - 提取所有
TableOne中不重复的type值,批量查询对应的TableTwo列表:List<TableTwo> findByTypeIn(Collection<String> types); - 在Service层将
TableTwo按type分组,然后逐个匹配到对应的TableOne,组装成目标结构:// 示例代码 List<TableOne> tableOneList = tableOneRepository.findAll(); Set<String> types = tableOneList.stream().map(TableOne::getType).collect(Collectors.toSet()); List<TableTwo> tableTwoList = tableTwoRepository.findByTypeIn(types); Map<String, List<TableTwo>> typeToTwoMap = tableTwoList.stream() .collect(Collectors.groupingBy(TableTwo::getType)); // 若TableTwo无type字段,替换为实际关联字段 List<Object[]> result = new ArrayList<>(); for (TableOne one : tableOneList) { result.add(new Object[]{one, typeToTwoMap.getOrDefault(one.getType(), Collections.emptyList())}); }
方案2:PostgreSQL JSON聚合+原生SQL
利用PostgreSQL的json_agg函数直接在SQL层完成聚合,返回结构化结果:
- 编写原生SQL,关联两张表并聚合
TableTwo为JSON数组:SELECT t1.id, t1.common_field, t1.type, t1.spec_id, json_agg(t2) AS table_two_list FROM table_one t1 LEFT JOIN table_two t2 ON t1.type = t2.type -- 调整为实际关联条件 GROUP BY t1.id, t1.common_field, t1.type, t1.spec_id - 自定义DTO接收结果:
@Data public class TableOneWithTwoList { private UUID id; private String commonField; private String type; private String specId; private List<TableTwo> tableTwoList; } - 在Repository中使用
@Query注解调用原生SQL,Spring Data会自动将JSON数组映射为List<TableTwo>:@Query(value = "SELECT t1.id, t1.common_field, t1.type, t1.spec_id, json_agg(t2) AS table_two_list FROM table_one t1 LEFT JOIN table_two t2 ON t1.type = t2.type GROUP BY t1.id, t1.common_field, t1.type, t1.spec_id", nativeQuery = true) List<TableOneWithTwoList> findOneWithTwoList();
方案3:Hibernate关联映射(适合长期业务绑定)
如果业务上TableOne和TableTwo存在稳定的关联关系,可直接在实体类中添加@OneToMany关联:
- 修改
TableOne实体,添加关联注解:@Data @Entity(name = "table_one") @Table(name = "table_one") public class TableOne { @Id @GeneratedValue private UUID id; private String commonField; private String type; private String specId; // 关联同type的TableTwo列表,insertable/updatable设为false避免影响原有表结构 @OneToMany @JoinColumn(name = "type", referencedColumnName = "type", insertable = false, updatable = false) private List<TableTwo> tableTwoList; } - 查询时使用
fetch join避免N+1问题:
此时返回的每个@Query("SELECT o FROM table_one o JOIN FETCH o.tableTwoList") List<TableOne> findAllWithTwoList();TableOne对象已包含对应的TableTwo列表,直接组装成目标结构即可。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

