You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并两个HQL统计查询?单次调用数据库获取两类结果

合并两类统计查询为单次数据库调用的方案

问题描述

我有两类统计查询需求:

  • 按type_id分组统计所有记录(无论is_read状态)的distinct ta.id数量,后续在Java代码中汇总各组总数;
  • 统计所有is_read='N'的记录的distinct ta.id总数。

目前需要两次调用数据库分别执行这两个查询,希望合并为单次数据库调用同时获取两类结果,实际使用HQL编写查询,以下是便于理解的SQL版本:

原查询1:按type_id分组统计全状态记录

-- 统计所有状态下的记录,后续在Java中汇总各组总数
select type_id as type, count(distinct ta.id) as totalId 
  from tableA as ta 
       inner join tableB tb on ta.id = tb.id 
       inner join tableC tc on tb.col1= tc.col2 
 where tc.col2= 6 
   and tb.is_deleted = 'N' 
 group by type_id

原查询2:统计未读记录总数

-- 仅统计未读(is_read='N')的记录总数
select count(distinct ta.id) as totalId 
  from tableA as ta 
       inner join tableB tb on ta.id =tb.id 
       inner join tableC tc on tb.col1 = tc.col2 
 where tc.col2= 6 
   and tb.is_deleted = 'N'
   and tb.is_read = 'N' 

解决方案

完全可以通过条件聚合或者union all的方式把两个查询合并成一次调用,同时拿到你需要的两类结果,而且写法兼容HQL,下面给你两种可行方案:

方案一:条件聚合+子查询(推荐)

这种方式会在每条分组记录里同时返回该分组的全状态统计数,以及全局的未读总数,结果结构更规整:

select 
  type_id as type,
  count(distinct ta.id) as totalAllStatus, -- 对应原查询1的分组统计结果
  max(global_unread.total) as globalUnreadTotal -- 对应原查询2的全局未读总数
from tableA ta
inner join tableB tb on ta.id = tb.id
inner join tableC tc on tb.col1 = tc.col2
-- 子查询单独计算全局未读总数,用cross join把这个值带到每一行
cross join (
  select count(distinct ta_inner.id) as total
  from tableA ta_inner
  inner join tableB tb_inner on ta_inner.id = tb_inner.id
  inner join tableC tc_inner on tb_inner.col1 = tc_inner.col2
  where tc_inner.col2 = 6
    and tb_inner.is_deleted = 'N'
    and tb_inner.is_read = 'N'
) global_unread
where tc.col2 = 6
  and tb.is_deleted = 'N'
group by type_id, global_unread.total
  • totalAllStatus:每个type_id下所有状态的去重ta.id数量,和原查询1结果完全一致;
  • globalUnreadTotal:所有未读记录的去重ta.id总数,每条分组返回的该值都相同,在Java中取任意一条的该值即可;
  • 若需要每个分组自身的未读数量,可额外添加count(distinct case when tb.is_read = 'N' then ta.id end) as groupUnread,按需调整。

方案二:用union all合并结果集

这种方式把两个查询的结果拼在一起,用标识字段区分数据类型,适合需要明确分开两类结果的场景:

-- 第一部分:原查询1的分组统计
select type_id as type, count(distinct ta.id) as count, 'all_group' as statType
from tableA ta
inner join tableB tb on ta.id = tb.id
inner join tableC tc on tb.col1 = tc.col2
where tc.col2 = 6 and tb.is_deleted = 'N'
group by type_id

union all

-- 第二部分:原查询2的全局未读总数
select null as type, count(distinct ta.id) as count, 'unread_total' as statType
from tableA ta
inner join tableB tb on ta.id = tb.id
inner join tableC tc on tb.col1 = tc.col2
where tc.col2 = 6 and tb.is_deleted = 'N' and tb.is_read = 'N'
  • statType为all_group的行是按type_id分组的统计数据;
  • statType为unread_total的行是全局未读总数,type字段为null用于占位,保证两边查询列数、类型一致;
  • HQL完全支持union all,只要两边查询的列匹配即可。

HQL适配注意点

  • 两种方案的语法都兼容HQL,子查询、case when、union all在主流Hibernate版本中均可正常运行;
  • 若使用较老的HQL版本,cross join可替换为无on条件的join,效果一致。

内容的提问来源于stack exchange,提问作者blueSky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 22:48:12