选择 H2 数据库要求按列分组的案例

Posted

技术标签:

【中文标题】选择 H2 数据库要求按列分组的案例【英文标题】:select case with H2 database asking to group by column 【发布时间】:2020-04-21 10:50:14 【问题描述】:

当我使用 HQL 查询我的数据库时,此请求工作正常并返回良好的数据:

    select
    case 
        when activityjp0_.status<>'CLOSED' 
        and (activityjp0_.user_id is null) then 'UNASSIGNED' 
        else case 
            when activityjp0_.status<>'CLOSED' 
            and activityjp0_.deadline<CURRENT_DATE then 'OVERDUE' 
            else case 
                when activityjp0_.status='PENDING' then 'IN_PROGRESS' 
                else activityjp0_.status 
            end 
        end 
    end as col_0_0_,
    count(distinct activityjp0_.id) as col_1_0_ 
from
    activities activityjp0_ 
group by
    case 
        when activityjp0_.status<>'CLOSED' 
        and (activityjp0_.user_id is null) then 'UNASSIGNED' 
        else case 
            when activityjp0_.status<>'CLOSED' 
            and activityjp0_.deadline<CURRENT_DATE then 'OVERDUE' 
            else case 
                when activityjp0_.status='PENDING' then 'IN_PROGRESS' 
                else activityjp0_.status 
            end 
        end 
    end

当我使用 Criteria API 生成 SAME 请求时,它给出:

    select
    case 
        when activityjp0_.status<>? 
        and (activityjp0_.user_id is null) then 'UNASSIGNED' 
        else case 
            when activityjp0_.status<>? 
            and activityjp0_.deadline<? then 'OVERDUE' 
            else case 
                when activityjp0_.status=? then 'IN_PROGRESS' 
                else activityjp0_.status 
            end 
        end 
    end as col_0_0_,
    count(distinct activityjp0_.id) as col_1_0_ 
from
    activities activityjp0_ 
group by
    case 
        when activityjp0_.status<>? 
        and (activityjp0_.user_id is null) then 'UNASSIGNED' 
        else case 
            when activityjp0_.status<>? 
            and activityjp0_.deadline<? then 'OVERDUE' 
            else case 
                when activityjp0_.status=? then 'IN_PROGRESS' 
                else activityjp0_.status 
            end 
        end 
    end

但这会导致 JDBC 错误声明:

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "ACTIVITYJP0_.USER_ID" must be in the GROUP BY list; SQL statement:

在activityjp0_.status时选择案例?和 (activityjp0_.user_id 为空) 然后是 'UNASSIGNED' 否则当 activityjp0_.status?和activityjp0_.deadline?和 (activityjp0_.user_id 为空) 然后是 'UNASSIGNED' 否则当 activityjp0_.status?和活动jp0_.deadline

如果我在同一个生成的查询中替换变量,并针对我的数据库(在 h2 控制台中)运行它,它运行时没有错误

这怎么可能?

【问题讨论】:

【参考方案1】:

你有两个非常相似的表达方式:

    case 
        when activityjp0_.status<>? 
        and (activityjp0_.user_id is null) then 'UNASSIGNED' 
        else case 
            when activityjp0_.status<>? 
            and activityjp0_.deadline<? then 'OVERDUE' 
            else case 
                when activityjp0_.status=? then 'IN_PROGRESS' 
                else activityjp0_.status 
            end 
        end 
    end

但实际上它们并不相同,因为参数(?)都是不同的;第一个表达式中有 4 个参数,第二个表达式中有 4 个附加参数。您应该使用group by col_0_0_ 而不是group by case … end,或者您可以在两个表达式中使用相同的索引(?1?2、...)参数。

【讨论】:

这个 sql 是由 hibernate(通过 format_sql=true 属性可见)从我的标准 API 代码生成的,所以我不能使用 ?1 ...我也无法使用生成的别名 col_0_0_也。我用纯 hql & :refDate 参数做了一个测试,它给出了同样的错误 PS:没有参数的纯 HQL(即硬写值)在 H2 中运行良好! 不幸的是,它对 H2 无效(可能对其他一些数据库),Hibernate 的分组查询存在许多已知问题。您的问题看起来像 HHH-11513,但可能是不同的问题。通常的解决方法是使用 Hibernate 的本机查询功能。 感谢澄清,这可能不是有效的 hql 请求。由于我的代码应该跨数据库工作,我不应该使用本机查询。我想我将删除 group by 子句并使用 Streams 将结果分组到内存中。奇怪的是,我们永远无法使用 Hibernate 进行性能优化请求。

以上是关于选择 H2 数据库要求按列分组的案例的主要内容,如果未能解决你的问题,请参考以下文章

按列分组,优先选择另一列不为空的行

100天精通Python(数据分析篇)——第64天:Pandas分组groupby函数案例

SUM 值按列分组,但不能“聚合”?

如何在 Hive 中除按列分组之外的列上应用 max 子句

熊猫数据框按列位置分组

按列对分组数据帧进行采样