Sql 带有内部SELECT语句的JPA条件生成器查询

Sql 带有内部SELECT语句的JPA条件生成器查询,sql,spring-boot,spring-data-jpa,criteria-api,self-join,Sql,Spring Boot,Spring Data Jpa,Criteria Api,Self Join,我需要使用JPA criteria builder创建以下SQL连接条件 SELECT * FROM student s1 INNER JOIN (SELECT subject,teacher,MIN(marks) AS marks FROM student GROUP BY subject, teacher) s2 ON s1.subject = s2.subject AND s1.teacher = s2.teacher AND s1.marks = s2.marks 下面是实体类和JPA

我需要使用JPA criteria builder创建以下SQL连接条件

SELECT * FROM student s1
INNER JOIN
(SELECT subject,teacher,MIN(marks) AS marks FROM student GROUP BY subject, teacher) s2
ON s1.subject = s2.subject
AND s1.teacher = s2.teacher
AND s1.marks = s2.marks
下面是实体类和JPA查询生成器

@Entity
@JsonIgnoreProperties(ignoreUnknown = true)
public class Student implements Serializable {
    
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="id")
    Long id;
    
    @Column(name="name")
    String name;
    
    @Column(name="subject")
    public
    String subject;
    
    @Column(name="teacher")
    String teacher;
    
    @Column(name="marks")
    String marks;
    
    @JsonIgnore
    @ManyToOne
    @JoinColumns({
    @JoinColumn(insertable=false, updatable=false, name="subject",referencedColumnName="subject"),
    @JoinColumn(insertable=false, updatable=false, name="teacher",referencedColumnName="teacher"),
    @JoinColumn(insertable=false, updatable=false, name="marks",referencedColumnName="marks")
    })
    Student studentSelf;
    
    @JsonIgnore
    @OneToMany(cascade = CascadeType.ALL, mappedBy="studentSelf")
    Set<Student> studentref;
@实体
@JsonIgnoreProperties(ignoreUnknown=true)
公共类学生实现可序列化{
私有静态最终长serialVersionUID=1L;
@身份证
@列(name=“id”)
长id;
@列(name=“name”)
字符串名;
@列(name=“subject”)
公众的
字符串主题;
@列(name=“teacher”)
弦乐教师;
@列(name=“marks”)
字符串标记;
@杰索尼奥雷
@许多酮
@连接柱({
@JoinColumn(insertable=false,updateable=false,name=“subject”,referencedColumnName=“subject”),
@JoinColumn(insertable=false,updateable=false,name=“teacher”,referencedColumnName=“teacher”),
@JoinColumn(insertable=false,updateable=false,name=“marks”,referencedColumnName=“marks”)
})
学生自我;
@杰索尼奥雷
@OneToMany(cascade=CascadeType.ALL,mappedBy=“studentSelf”)
设置studentref;
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery=cb.createQuery(Student.class);
Root-mainStudent=query.from(Student.class);
列表谓词=新的ArrayList();
Join-studentJoin=mainStudent.Join(“studentSelf”,JoinType.INNER);
List List=entityManager.createQuery(query.getResultList();
我可以使用join条件生成查询,但无法创建内部SELECT查询。如何为join子句创建内部SELECT查询

需求描述:以下是所需的输入表和输出


我还没有试过这个,但它失败得很惨,只有一个例外。但是你能试一试吗

  • 如果您只是为了此查询而添加了
    studentSelf
    studentRef
    ,请删除它们。studentSelf`上的多个
    也不是,因为它将指向多个记录

  • 我认为下面的查询相当于您试图实现的目标

  • 然后我尝试将其转换为
    CriteriaQuery
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery=cb.createQuery(Student.class);
Root-mainStudent=query.from(Student.class);
Subquery Subquery=query.Subquery(Student.class);
Root subQueryRoot=subQuery.from(Student.class);
谓词谓词1=cb.equal(mainStudent.get(“教师”),
subQueryRoot.get(“教师”);
谓词predicate2=cb.equal(mainStudent.get(“主语”),
subQueryRoot.get(“主题”);
谓词finalPredicate=cb.and(谓词1,谓词2);
subQuery.select(cb.min(subQueryRoot.get(“marks”)).where(finalPredicate);
query.select(mainStudent).where(mainStudent.get(“marks”).in(子查询));
em.createQuery(issueQuery).getResultList();
更新


更新了
subquery.correlate(mainStudent);
subquery.from(Student.class);
基于
vinay-s-g
注释

对上述答案所做的微小更改

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Student> query = cb.createQuery(Student.class);
        Root<Student> mainStudent = query.from(Student.class);

        Subquery<Student> subQuery = query.subquery(Student.class);
        Root subQueryRoot = subQuery.from(Student.class);

        Predicate predicate1 = cb.equal(mainStudent.get("teacher"), 
                                        subQueryRoot.get("teacher"));
        Predicate predicate2 = cb.equal(mainStudent.get("subject"), 
                                        subQueryRoot.get("subject"));
        Predicate finalPredicate = cb.and(predicate1, predicate2);

        subQuery.select(cb.min(subQueryRoot.get("marks"))).where(finalPredicate);

        query.select(mainStudent).where(mainStudent.get("marks").in(subQuery));
        return entityManager.createQuery(query).getResultList();
CriteriaBuilder cb=entityManager.getCriteriaBuilder();
CriteriaQuery=cb.createQuery(Student.class);
Root-mainStudent=query.from(Student.class);
Subquery Subquery=query.Subquery(Student.class);
Root subQueryRoot=subQuery.from(Student.class);
谓词谓词1=cb.equal(mainStudent.get(“教师”),
subQueryRoot.get(“教师”);
谓词predicate2=cb.equal(mainStudent.get(“主语”),
subQueryRoot.get(“主题”);
谓词finalPredicate=cb.and(谓词1,谓词2);
subQuery.select(cb.min(subQueryRoot.get(“marks”)).where(finalPredicate);
query.select(mainStudent).where(mainStudent.get(“marks”).in(子查询));
返回entityManager.createQuery(query.getResultList();

一种方法可能是使用
WHERE
子句中的相关子查询来重新编写查询,以检查最小分数值。但我正在尝试根据教师和科目的唯一组合提取最小分数。相关子查询可能有助于满足此要求。我正在尝试了解您的模型以及而
studentSelf
不是一个
@manytone
关系(即
subject
teacher
marks
不能唯一地识别学生)。如果你想保留
studentRef
(代表
同学
)作为单向
@OneToMany
@kavithakarankapathippillai,要求提取科目和教师的每个组合的最低分数。我在查询中添加了要求。我还没有尝试解决方案。我将等待OP的反馈,如果不起作用,将设置一个样本和实验。谢谢@KavithakaranKanapathippillai,您的解决方案进行了一些小改动。但问题仍然存在,我们不能使用Hibernate加入SELECT查询。我正在尝试使用API EasyCriteria 2.0,但仍然无法做到。我将更新答案以供参考。关于第二个问题,只有当我们正在初始化JPQL或HQL。使用JPA标准API时,此功能不可用
    SELECT * 
    FROM student s1
    WHERE s1.marks 
    IN
    (
      SELECT MIN(s2.marks) 
      FROM student s2
      where s1.subject = s2.subject
      AND  s1.teacher = s2.teacher
    )
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Student> query = cb.createQuery(Student.class);
    Root<Student> mainStudent = query.from(Student.class);

    Subquery<Student> subQuery = query.subquery(Student.class);
    Root<Student> subQueryRoot = subQuery.from(Student.class);

    Predicate predicate1 = cb.equal(mainStudent.get("teacher"), 
                                    subQueryRoot.get("teacher"));
    Predicate predicate2 = cb.equal(mainStudent.get("subject"), 
                                    subQueryRoot.get("subject"));
    Predicate finalPredicate = cb.and(predicate1, predicate2);

    subQuery.select(cb.min(subQueryRoot.get("marks"))).where(finalPredicate);

    query.select(mainStudent).where(mainStudent.get("marks").in(subQuery));
    em.createQuery(issueQuery).getResultList();
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<Student> query = cb.createQuery(Student.class);
        Root<Student> mainStudent = query.from(Student.class);

        Subquery<Student> subQuery = query.subquery(Student.class);
        Root subQueryRoot = subQuery.from(Student.class);

        Predicate predicate1 = cb.equal(mainStudent.get("teacher"), 
                                        subQueryRoot.get("teacher"));
        Predicate predicate2 = cb.equal(mainStudent.get("subject"), 
                                        subQueryRoot.get("subject"));
        Predicate finalPredicate = cb.and(predicate1, predicate2);

        subQuery.select(cb.min(subQueryRoot.get("marks"))).where(finalPredicate);

        query.select(mainStudent).where(mainStudent.get("marks").in(subQuery));
        return entityManager.createQuery(query).getResultList();