复杂的JPQL查询,用于列出所有归档中的上次创建的文件

时间:2014-05-30 18:30:53

标签: java sql hibernate jpa jpql

我有这个数据库结构:

CREATE TABLE `archive` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `version` bigint(20) NOT NULL,
  `name` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
  `employee_id` bigint(20) NOT NULL,
  `subcategory_id` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_pnk12l4936a21pst3p696mgt6` (`name`),
  KEY `fk_archive_employee` (`employee_id`),
  KEY `fk_archive_subcategory` (`subcategory_id`)
)


CREATE TABLE `archive_file` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `version` bigint(20) NOT NULL,
  `created` datetime NOT NULL,
  `edition` varchar(4) COLLATE utf8_unicode_ci NOT NULL,
  `expire` date NOT NULL,
  `history` text COLLATE utf8_unicode_ci NOT NULL,
  `mime_type` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
  `archive_id` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UK_lgh85dj5mtjkevbkmgl8q0rso` (`name`),
  KEY `fk_archive_file_archive` (`archive_id`)
)

这个java实体:

Archive.java

@Entity
@Table(name = "archive")
public class Archive extends AbstractEntity {

   @NotEmpty
   @Size(max = ConstantNumeric.TWO_HUNDRED)
   @Column(name = "name", length = ConstantNumeric.TWO_HUNDRED, unique = true)
   private String name;

   @NotEmpty
   @ManyToOne
   @JoinColumn(name = "subcategory_id")
   @ForeignKey(name = FK + "subcategory")
   private ArchiveCategory subcategory;

   @NotEmpty
   @OneToMany(mappedBy = "archive", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
   private List<ArchiveFile> files;

   @NotEmpty
   @ManyToOne
   @JoinColumn(name = "employee_id")
   @ForeignKey(name = FK + "employee")
   private Employee responsible;

   @NotEmpty
   @AuditJoinTable(inverseJoinColumns = @JoinColumn(name = "department_id"))
   @ManyToMany
   @JoinTable(name = "archive_has_department", joinColumns = @JoinColumn(name = "archive_id"),
            inverseJoinColumns = @JoinColumn(name = "department_id"))
   @ForeignKey(name = FK + "has_department", inverseName = FK + "department")
   private List<Department> departments;

...Getters/Settters

ArchiveFile.java

@Entity
@Table(name = "archive_file")
public class ArchiveFile extends AbstractEntity {

   @NotEmpty
   @Size(max = ConstantNumeric.TWO_HUNDRED)
   @Column(name = "name", unique = true, length = ConstantNumeric.TWO_HUNDRED, updatable = false)
   private String name;

   @NotEmpty
   @Size(max = ConstantNumeric.FOUR)
   @Column(name = "edition", length = ConstantNumeric.FOUR, updatable = false)
   private String edition;

   @NotEmpty
   @Temporal(TemporalType.DATE)
   @Column(name = "expire", updatable = false)
   private Date expire;

   @NotEmpty
   @Temporal(TemporalType.TIMESTAMP)
   @Column(name = "created", updatable = false)
   private Date created;

   @NotEmpty
   @Column(columnDefinition = "text", updatable = false)
   private String history;

   @NotEmpty
   @ManyToOne(cascade = CascadeType.ALL, optional = false)
   @JoinColumn(name = "archive_id", referencedColumnName = "id")
   @ForeignKey(name = "fk_archive_file_archive")
   private Archive archive;

   @NotEmpty
   @Column(name = "mime_type", updatable = false)
   private String mimeType;

...Getters/Settters

有了这个我需要所有档案最后创建的archive_file 一个SQL查询来执行此操作,例如:

SELECT * FROM archive AS a 
INNER JOIN archive_file as af 
WHERE af.id IN(SELECT a.id FROM 
(SELECT * FROM archive_file AS af WHERE  af.created > '2012-05-30' 
ORDER BY af.created DESC) AS a GROUP BY a.archive_id) AND a.id = af.archive_id  

结果是:

+----+---------+--------------------------+-------------+----------------+----+---------+---------------------+---------+------------+-----------------------+--------------+-----------------+------------+
| id | version | name                     | employee_id | subcategory_id | id | version | created             | edition | expire     | history               | mime_type    | name            | archive_id |
+----+---------+--------------------------+-------------+----------------+----+---------+---------------------+---------+------------+-----------------------+--------------+-----------------+------------+
|  1 |       1 | Archive shouldUpdateDAO  |           1 |              4 |  1 |       0 | 2014-05-31 14:41:27 | 1       | 2014-06-04 | history sholdSaveDAO  | document/pdf | SHOULDSAVEDAO   |          1 |
|  2 |       0 | Archive ShouldGetByIdDAO |           1 |              2 |  3 |       0 | 2014-05-30 14:41:27 | 1       | 2014-05-30 | history shouldGetById | document/pdf | SHOUDGETBYIDDAO |          2 |
+----+---------+--------------------------+-------------+----------------+----+---------+---------------------+---------+------------+-----------------------+--------------+-----------------+------------+
2 rows in set (0.00 sec)

但是我需要用JPQL来做这件事,我试过这个没有成功:

final String sql = "SELECT archive FROM archive AS a INNER JOIN archive_file as af " +
                   "WHERE af.id in (SELECT a.id FROM (SELECT archive_file FROM archive_file AS af " +
                   "WHERE  af.created > '2012-05-30' ORDER BY af.created DESC) AS a " +
                   "GROUP BY a.archive_id) AND a.id = af.archive_id";

TypedQuery<Archive> query = getEm().createQuery(sql, Archive.class);

抛出异常,因为这不是有效的JPQL查询:

  

javax.ejb.EJBException:java.lang.IllegalArgumentException:   org.hibernate.hql.internal.ast.QuerySyntaxException:意外令牌:   (靠近第1行,第97列[SELECT archive FROM archive as a INTERNER JOIN   archive_file as af WHERE af.id in(SELECT a.id FROM(SELECT   archive_file FROM archive_file AS af af afcreated&gt; '2012-05-30'   ORDER BY af.created DESC)as a group by a.archive_id)AND a.id =   af.archive_id]

有一种方法可以在JPQL中执行此操作吗?如果没有,你会用什么方法? SQL本机查询,Criteria还是什么?

2 个答案:

答案 0 :(得分:0)

你需要什么subquerys?

仅使用内连接不会起作用吗?

SELECT
   * 
FROM
   archive AS a   
INNER JOIN
   archive_file as af ON af.archive_id= a.id  
WHERE
  af.created > '2012-05-30'

猜测我没有任何数据。

修改

没有subquerys的查询可能如下所示:

SELECT
  a.*, af.id as aid, af.created, af.archive_id 
FROM
  archive AS a   
INNER JOIN
  archive_file as af ON af.archive_id= a.id 
LEFT JOIN
  archive_file as af2 ON af2.archive_id= af.archive_id
  AND af2.created > af.created
WHERE
  af.created > '2012-05-30' and
  af2.created is null

sql fiddle here

答案 1 :(得分:0)

您的SQL查询可以重写为:

SELECT DISTINCT a.* FROM archive a, archive_file af WHERE a.id = af.archive_id AND af.created > '2012-05-30'

它映射到以下JPQL查询:

SELECT DISTINCT a FROM archive a WHERE a.files.created > '2012-05-30'