带元组条件的 QueryDSL 和子查询

问题描述 投票:0回答:5

我正在尝试在 QueryDSL 中编写一个查询来获取按其parentId分组的表中最旧的元素。

SQL 等效项应该是:

SELECT a.* FROM child a
    INNER JOIN
    (
        SELECT parentId, MAX(revision) FROM child GROUP BY parentId
    ) b
    ON ( 
        a.parentId = b.parentId AND a.revision = b.revision
    )

现在在 QueryDSL 中我被语法困住了。

JPQLQuery<Tuple> subquery = JPAExpressions
                .select(child.parent, child.revision.max())
                .from(child)
                .groupBy(child.parent);

HibernateQuery<Child> query = new HibernateQuery<>(session);
query.from(child)
    .where(child.parent.eq(subquery.???).and(child.revision.eq(subquery.???))));

如何使用子查询编写此查询?

桌子看起来像这样:

___parent___(此查询中未使用,但存在)
父ID
P1 | *
P2 | *
P3 | *

___孩子___
父 ID |修订
P1 | 1 | *
P1 | 2 | *
P1 | 3 | *
P2 | 2 | *
P2 | 3 | *
P3 | 1 | *

___来自子项的结果,每个父项 ID 的最高版本___
P1 | 3 | *
P2 | 3 | *
P3 | 1 | *

到目前为止我尝试过的:

.where(JPAExpressions.select(child.parent,child.revision).eq(subquery));

-> org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected end of subtree

还有许多语法错误...

我现在使用脏循环,因为我还没有找到解决方案。

java hibernate jpa syntax querydsl
5个回答
6
投票

您可以使用

Expressions.list()
为 in 子句指定多于一列:

query.from(child).where(Expressions.list(child.parent, child.revision).in(subquery));

替代方法是使用

innerJoin()
,如在原始 SQL 中一样。


3
投票
Expressions.list(ENTITY.year, ENTITY.week).in(//
                    Expressions.list(Expressions.constant(1029), Expressions.constant(1)),
                    Expressions.list(Expressions.constant(1030), Expressions.constant(1)),
                    Expressions.list(Expressions.constant(1031), Expressions.constant(1))

将是您正在寻找的内容,但 QueryDSL 从中生成错误的 SQL:

((p0_.year , p0_.week) in (1029 , 1 , (1030 , 1) , (1031 , 1)))

1
投票

在JPA中子查询只能出现在where部分。

这是我对您的询问的看法

select(child).from(child).where(child.revision.eq(
  select(child2.revision.max())
 .from(child2)
 .where(child2.parent.eq(child.parent))
 .groupBy(child2.parent))).fetch()

1
投票

基于 JRA_TLL 的答案构建 - 根据 QueryDSL 维护者的说法,

Expressions.list()
的嵌套使用是不支持。选择报价:

这并不是真正的错误,只是对 QueryDSL 的内部

list
元组表达式的不当使用。

[...]

解决方案非常简单:不要使用列表表达式。这使用了

Template
表达式。

这是 JRA_TLL 的答案,采用维护者推荐的

Template
范式,它做了正确的事情:

public static SimpleExpression<Object> tuple(Expression<?>... args) {
    return Expressions.template(Object.class, "({0}, {1})", args);
}

// ...

Expressions.list(ENTITY.year, ENTITY.week).in(
    tuple(Expressions.constant(1029), Expressions.constant(1)),
    tuple(Expressions.constant(1030), Expressions.constant(1)),
    tuple(Expressions.constant(1031), Expressions.constant(1)));

这应该生成正确的 SQL:

(p0_.year , p0_.week) in ((1029 , 1) , (1030 , 1) , (1031 , 1))

请注意,这种查询构造并不适用于所有类型的数据库;例如,这在 PostgresSQL 中有效,但在 Microsoft SQL Server 中无效。


0
投票

我在mysql中也遇到异常

使用者:异常 [EclipseLink-4002](Eclipse 持久性服务 - 2.7.11.v20220804-52dea2a3c0):org.eclipse.persistence.exceptions.DatabaseException 内部异常:java.sql.SQLException:操作数应包含 2 列 错误代码:1241 调用: SELECT FOUNDING_YEAR、UNIVERSITY_NAME、JSON_STORE、EXT_COUNTRY、STATE、CREATED_TIMESTAMP、PK FROM ORG_UNIVERSITY WHERE ((ORG_ID = ?) AND ((STATE, UNIVERSITY_NAME) IN (?,?))) 绑定 => [系统, ({a}, {b}), ({c}, {d})] 查询: ReportQuery(referenceClass=UniversityEntity sql="SELECT FOUNDING_YEAR, UNIVERSITY_NAME, JSON_STORE, EXT_COUNTRY, STATE, CREATED_TIMESTAMP, PK FROM ORG_UNIVERSITY WHERE ((ORG_ID = ?) AND ((STATE, UNIVERSITY_NAME) IN ?))")

有什么建议请留言

© www.soinside.com 2019 - 2024. All rights reserved.