JPA select 每个项目只有最近的日期
JPA select only the most recent dates per item
所以我有一个有效的 jpa 数据库查询,returns 来自那个 table 的所有 SiteBmdfBusinessDay,并通过加入它们的 ID 列将它们关联到它们相应的 SiteBmdf。我想要做的是,不是获取所有 SiteBmdfBusinessDay,而是只想获取最近的 businessDay。
这是 SiteBmdfBusinessDay class...
@Entity
public class SiteBmdfBusinessDay extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private SiteBmdf siteBmdf;
private DateTime businessDay;
private Long failedCount;
private DateTime lastSuccessfulBusinessDay;
private DateTime lastSuccessfulFullBusinessDay;
private Ticket ticket;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "site_bmdf_business_day_site_bmdf_business_day_id_seq")
@SequenceGenerator(name = "site_bmdf_business_day_site_bmdf_business_day_id_seq", sequenceName = "site_bmdf_business_day_site_bmdf_business_day_id_seq", allocationSize = 1)
@Column(name = "site_bmdf_business_day_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name = "site_bmdf_id")
public SiteBmdf getSiteBmdf() {
return siteBmdf;
}
public void setSiteBmdf(SiteBmdf siteBmdf) {
this.siteBmdf = siteBmdf;
}
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime", parameters = {
@Parameter(name = "databaseZone", value = "UTC"), @Parameter(name = "javaZone", value = "UTC") })
public DateTime getBusinessDay() {
return businessDay;
}
public void setBusinessDay(DateTime businessDay) {
this.businessDay = businessDay;
}
public Long getFailedCount() {
return failedCount;
}
public void setFailedCount(Long count) {
this.failedCount = count;
}
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime", parameters = {
@Parameter(name = "databaseZone", value = "UTC"), @Parameter(name = "javaZone", value = "UTC") })
public DateTime getLastSuccessfulBusinessDay() {
return lastSuccessfulBusinessDay;
}
public void setLastSuccessfulBusinessDay(DateTime lastSuccessfulBusinessDay) {
this.lastSuccessfulBusinessDay = lastSuccessfulBusinessDay;
}
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime", parameters = {
@Parameter(name = "databaseZone", value = "UTC"), @Parameter(name = "javaZone", value = "UTC") })
public DateTime getLastSuccessfulFullBusinessDay() {
return lastSuccessfulFullBusinessDay;
}
public void setLastSuccessfulFullBusinessDay(DateTime lastSuccessfulFullBusinessDay) {
this.lastSuccessfulFullBusinessDay = lastSuccessfulFullBusinessDay;
}
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "ticket_id")
public Ticket getTicket() {
return ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
}
和 SiteBmdf class...
@Entity
public class SiteBmdf extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String site;
private Long failureCount;
private Set<SiteBmdfBusinessDay> businessDays;
private List<SiteBmdfNote> notes;
private Resolution resolution;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "site_bmdf_site_bmdf_id_seq")
@SequenceGenerator(name = "site_bmdf_site_bmdf_id_seq", sequenceName = "site_bmdf_site_bmdf_id_seq", allocationSize = 1)
@Column(name = "site_bmdf_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSite() {
return site;
}
public void setSite(String site) {
this.site = site;
}
@Transient
public Long getFailureCount() {
return failureCount;
}
public void setFailureCount(Long failureCount) {
this.failureCount = failureCount;
}
@JsonIgnore
@OneToMany(mappedBy = "siteBmdf", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<SiteBmdfBusinessDay> getBusinessDays() {
return this.businessDays;
}
public void setBusinessDays(Set<SiteBmdfBusinessDay> businessDays) {
this.businessDays = businessDays;
}
@OneToMany(mappedBy = "siteBmdf", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public List<SiteBmdfNote> getNotes() {
Collections.sort(notes);
return notes;
}
public void setNotes(List<SiteBmdfNote> notes) {
this.notes = notes;
}
@ManyToOne
@JoinColumn(name = "resolutionId")
public Resolution getResolution() {
return resolution;
}
public void setResolution(Resolution resolution) {
this.resolution = resolution;
}
}
这里是当前的查询方式....
@Override
public PageImpl<SiteBmdfBusinessDay> bmdfSitePaged(UiBuildCriteria criteria) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<SiteBmdfBusinessDay> query = builder.createQuery(SiteBmdfBusinessDay.class);
Root<SiteBmdfBusinessDay> root = query.from(SiteBmdfBusinessDay.class);
if (!criteria.getSearch().getPredicateObject().isEmpty()) {
List<Predicate> predicates = predicateBuilderService.buildPredicates(builder, root, criteria.getSearch());
query.where(builder.and(predicates.toArray(new Predicate[] {})));
}
query.select(root);
builder.max(root.<Long>get("businessDay"));
// get the count for PageImpl
Long total = this.count(criteria);
// Set the order by
List<CustomSort> defaultSorts = new ArrayList<CustomSort>(
Arrays.asList(
new CustomSort("businessDay", Boolean.TRUE),
new CustomSort("siteBmdf.site", Boolean.FALSE)
));
List<Order> orders = sortOrderBuilderService.buildSort(builder, root, criteria.getSort(), defaultSorts);
query.orderBy(orders);
List<SiteBmdfBusinessDay> content = entityManager.createQuery(query).setFirstResult(criteria.getPagination().getStart())
.setMaxResults(criteria.getPagination().getNumber()).getResultList();
return new PageImpl<>(content, criteria.getPageRequest(), total);
}
正如我所说,当前结果只是 SiteBmdfBusinessDay table 中的所有项目及其相应的 SiteBmdf。我只想要每个网站的最近营业日的 SiteBmdfBusinessDays。
例如,如果我有 table site_bmdf_business_day:
site_bmdf_business_day_id | site_bmdf_id | business_day
1 | 1 | 6/1/2011
2 | 2 | 6/1/2011
3 | 1 | 6/6/2011
4 | 3 | 6/6/2011
我只想显示:
site_bmdf_business_day_id | site_bmdf_id | business_day
2 | 2 | 6/1/2011
3 | 1 | 6/6/2011
4 | 3 | 6/6/2011
我知道我需要一些类似 builder.max(root.get("businessDay")) 的东西,但我不确定如何实现它。
如有任何帮助,我们将不胜感激。
请注意 this question 类似,但不完全是我要找的,因为所有答案都在 SQL 中,我需要 jpa 中的一些东西。
对于这些类型的查询,我通常将其归结为 sql(没有分页和其他限制),然后将其反向构造为查询构建器。它使 IMO 代码更清晰。你要找的是
select a.* from SiteBmdfBusinessDay a
inner join
( select site_bmdf_id, max (business_day) as business_day
from SiteBmdfBusinessDay group by site_bmdf_id ) b
on (a.site_bmdf_id = b.site_bmdf_id) and (a.business_day = b.business_day)
这假设每天最多有一个条目,site_bmdf_id。
据我所知,这作为构建器是不可行的,但是,您可以将其作为创建查询,它工作得很好(因为结果只是一个普通实体。)但是,它是一个假设您有大量数据,性能非常高的查询。除非你有一个小数据集,否则最好把它全部拿走,然后以编程方式过滤掉重复项(你应该能够在 O(n) 时间内完成。)
所以我有一个有效的 jpa 数据库查询,returns 来自那个 table 的所有 SiteBmdfBusinessDay,并通过加入它们的 ID 列将它们关联到它们相应的 SiteBmdf。我想要做的是,不是获取所有 SiteBmdfBusinessDay,而是只想获取最近的 businessDay。
这是 SiteBmdfBusinessDay class...
@Entity
public class SiteBmdfBusinessDay extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private SiteBmdf siteBmdf;
private DateTime businessDay;
private Long failedCount;
private DateTime lastSuccessfulBusinessDay;
private DateTime lastSuccessfulFullBusinessDay;
private Ticket ticket;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "site_bmdf_business_day_site_bmdf_business_day_id_seq")
@SequenceGenerator(name = "site_bmdf_business_day_site_bmdf_business_day_id_seq", sequenceName = "site_bmdf_business_day_site_bmdf_business_day_id_seq", allocationSize = 1)
@Column(name = "site_bmdf_business_day_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name = "site_bmdf_id")
public SiteBmdf getSiteBmdf() {
return siteBmdf;
}
public void setSiteBmdf(SiteBmdf siteBmdf) {
this.siteBmdf = siteBmdf;
}
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime", parameters = {
@Parameter(name = "databaseZone", value = "UTC"), @Parameter(name = "javaZone", value = "UTC") })
public DateTime getBusinessDay() {
return businessDay;
}
public void setBusinessDay(DateTime businessDay) {
this.businessDay = businessDay;
}
public Long getFailedCount() {
return failedCount;
}
public void setFailedCount(Long count) {
this.failedCount = count;
}
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime", parameters = {
@Parameter(name = "databaseZone", value = "UTC"), @Parameter(name = "javaZone", value = "UTC") })
public DateTime getLastSuccessfulBusinessDay() {
return lastSuccessfulBusinessDay;
}
public void setLastSuccessfulBusinessDay(DateTime lastSuccessfulBusinessDay) {
this.lastSuccessfulBusinessDay = lastSuccessfulBusinessDay;
}
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime", parameters = {
@Parameter(name = "databaseZone", value = "UTC"), @Parameter(name = "javaZone", value = "UTC") })
public DateTime getLastSuccessfulFullBusinessDay() {
return lastSuccessfulFullBusinessDay;
}
public void setLastSuccessfulFullBusinessDay(DateTime lastSuccessfulFullBusinessDay) {
this.lastSuccessfulFullBusinessDay = lastSuccessfulFullBusinessDay;
}
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "ticket_id")
public Ticket getTicket() {
return ticket;
}
public void setTicket(Ticket ticket) {
this.ticket = ticket;
}
}
和 SiteBmdf class...
@Entity
public class SiteBmdf extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String site;
private Long failureCount;
private Set<SiteBmdfBusinessDay> businessDays;
private List<SiteBmdfNote> notes;
private Resolution resolution;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "site_bmdf_site_bmdf_id_seq")
@SequenceGenerator(name = "site_bmdf_site_bmdf_id_seq", sequenceName = "site_bmdf_site_bmdf_id_seq", allocationSize = 1)
@Column(name = "site_bmdf_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSite() {
return site;
}
public void setSite(String site) {
this.site = site;
}
@Transient
public Long getFailureCount() {
return failureCount;
}
public void setFailureCount(Long failureCount) {
this.failureCount = failureCount;
}
@JsonIgnore
@OneToMany(mappedBy = "siteBmdf", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<SiteBmdfBusinessDay> getBusinessDays() {
return this.businessDays;
}
public void setBusinessDays(Set<SiteBmdfBusinessDay> businessDays) {
this.businessDays = businessDays;
}
@OneToMany(mappedBy = "siteBmdf", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public List<SiteBmdfNote> getNotes() {
Collections.sort(notes);
return notes;
}
public void setNotes(List<SiteBmdfNote> notes) {
this.notes = notes;
}
@ManyToOne
@JoinColumn(name = "resolutionId")
public Resolution getResolution() {
return resolution;
}
public void setResolution(Resolution resolution) {
this.resolution = resolution;
}
}
这里是当前的查询方式....
@Override
public PageImpl<SiteBmdfBusinessDay> bmdfSitePaged(UiBuildCriteria criteria) {
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<SiteBmdfBusinessDay> query = builder.createQuery(SiteBmdfBusinessDay.class);
Root<SiteBmdfBusinessDay> root = query.from(SiteBmdfBusinessDay.class);
if (!criteria.getSearch().getPredicateObject().isEmpty()) {
List<Predicate> predicates = predicateBuilderService.buildPredicates(builder, root, criteria.getSearch());
query.where(builder.and(predicates.toArray(new Predicate[] {})));
}
query.select(root);
builder.max(root.<Long>get("businessDay"));
// get the count for PageImpl
Long total = this.count(criteria);
// Set the order by
List<CustomSort> defaultSorts = new ArrayList<CustomSort>(
Arrays.asList(
new CustomSort("businessDay", Boolean.TRUE),
new CustomSort("siteBmdf.site", Boolean.FALSE)
));
List<Order> orders = sortOrderBuilderService.buildSort(builder, root, criteria.getSort(), defaultSorts);
query.orderBy(orders);
List<SiteBmdfBusinessDay> content = entityManager.createQuery(query).setFirstResult(criteria.getPagination().getStart())
.setMaxResults(criteria.getPagination().getNumber()).getResultList();
return new PageImpl<>(content, criteria.getPageRequest(), total);
}
正如我所说,当前结果只是 SiteBmdfBusinessDay table 中的所有项目及其相应的 SiteBmdf。我只想要每个网站的最近营业日的 SiteBmdfBusinessDays。
例如,如果我有 table site_bmdf_business_day:
site_bmdf_business_day_id | site_bmdf_id | business_day
1 | 1 | 6/1/2011
2 | 2 | 6/1/2011
3 | 1 | 6/6/2011
4 | 3 | 6/6/2011
我只想显示:
site_bmdf_business_day_id | site_bmdf_id | business_day
2 | 2 | 6/1/2011
3 | 1 | 6/6/2011
4 | 3 | 6/6/2011
我知道我需要一些类似 builder.max(root.get("businessDay")) 的东西,但我不确定如何实现它。
如有任何帮助,我们将不胜感激。
请注意 this question 类似,但不完全是我要找的,因为所有答案都在 SQL 中,我需要 jpa 中的一些东西。
对于这些类型的查询,我通常将其归结为 sql(没有分页和其他限制),然后将其反向构造为查询构建器。它使 IMO 代码更清晰。你要找的是
select a.* from SiteBmdfBusinessDay a
inner join
( select site_bmdf_id, max (business_day) as business_day
from SiteBmdfBusinessDay group by site_bmdf_id ) b
on (a.site_bmdf_id = b.site_bmdf_id) and (a.business_day = b.business_day)
这假设每天最多有一个条目,site_bmdf_id。
据我所知,这作为构建器是不可行的,但是,您可以将其作为创建查询,它工作得很好(因为结果只是一个普通实体。)但是,它是一个假设您有大量数据,性能非常高的查询。除非你有一个小数据集,否则最好把它全部拿走,然后以编程方式过滤掉重复项(你应该能够在 O(n) 时间内完成。)