我正在尝试在 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
还有许多语法错误...
我现在使用脏循环,因为我还没有找到解决方案。
您可以使用
Expressions.list()
为 in 子句指定多于一列:
query.from(child).where(Expressions.list(child.parent, child.revision).in(subquery));
替代方法是使用
innerJoin()
,如在原始 SQL 中一样。
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)))
在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()
基于 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 中无效。
我在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 ?))")
有什么建议请留言