Hi devs,

Is it allowed to have use a "sub-sub-query" in JPQL? For instance, if I want to select publishers with last published magazines, I can use this select

  SELECT p, m
    FROM Publisher p
         LEFT OUTER JOIN p.magazineCollection m
   WHERE m.datePublished = (SELECT MAX(m3.datePublished)
                              FROM Magazine m3
                             WHERE m3.idPublisher.id = p.id)

But if I add another select, to make sure that ony one magazine per publisher is selected:

  SELECT p, m
    FROM Publisher p
         LEFT OUTER JOIN p.magazineCollection m
   WHERE m.id = (SELECT MAX(m2.id)
                   FROM Magazine m2
                  WHERE m2.idPublisher.id = p.id
                    AND m2.datePublished =
                          (SELECT MAX(m3.datePublished)
                             FROM Magazine m3
                            WHERE m3.idPublisher.id = p.id))

OpenJPA 1.2.0 translates this into native (MySQL) query:

SELECT t0.id, t1.id, t1.date_published, t1.id_publisher, t1.name
  FROM Publisher t0
       LEFT OUTER JOIN Magazine t1
          ON t0.id = t1.id_publisher
 WHERE (t1.id = (SELECT MAX(t4.id)
                   FROM Magazine t4
                  WHERE (t2.id_publisher = t0.id
                        AND t2.date_published =
                           (SELECT MAX(t3.date_published)
                              FROM Magazine t2, Magazine t3
                             WHERE (t3.id_publisher = t0.id)))))

and that query throws an exception:

NestedThrowables:
com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 't2.id_publisher' in 'where clause'


Note, in the first subquery the FROM clause declares t4, but WHERE clause references t2, which was daclared in the second subquery, and therefore not visible.

Also note, the second subquery selects from two tables "magazine", which is unnecessary.

Find the entity beans in the attachment.

Configuration:
- OpenJPA 1.2.0
- MySQL 5.0.22

Regards,
Ognjen
package magazine.model;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.OneToMany;
import java.util.Set;

@Entity
public class Publisher implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="name")
    private String name;

    @OneToMany(mappedBy="idPublisher")
    private Set<Magazine> magazineCollection;


    private static final long serialVersionUID = 1L;

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Magazine> getMagazineCollection() {
        return this.magazineCollection;
    }

    public void setMagazineCollection(Set<Magazine> magazineCollection) {
        this.magazineCollection = magazineCollection;
    }

    @Override
    public String toString() {
        return name;
    }
}
package magazine.model;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.FetchType;
import java.sql.Date;

@Entity
public class Magazine implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="name")
    private String name;
    
    @Column(name="date_published")
    private Date datePublished;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="id_publisher")
    private Publisher idPublisher;


    private static final long serialVersionUID = 1L;

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Publisher getIdPublisher() {
        return this.idPublisher;
    }

    public void setIdPublisher(Publisher idPublisher) {
        this.idPublisher = idPublisher;
    }
    
    public Date getDatePublished() {
        return datePublished;
    }

    public void setDatePublished(Date datePublished) {
        this.datePublished = datePublished;
    }

    @Override
    public String toString() {
        return name;
    }
}

Reply via email to