[英]How to make JPQL joins not double up results
我有一些使用JPA / JPQL和Hibernate引用项目的实体。
一个报价有很多报价项目,每个项目可以有0个或多个调整项。 每种调整都是折扣或附加费,或者是百分比(即商品价格的百分比)或金额(即固定值)
我正在尝试编写一个JPQL查询,该查询将为我提供给定地区,用户和时间段的所有报价的值,并将报价的每个报价项目的价格与任何调整的值相加。 我差一点就可以了,但这不是很正确。
String query = "select q.user, q.contact.parent.region, sum( case " +
" when a.type = :type_surcharge and a.amountType = :amount_type_percentage then ( a.amount * qi.price ) " +
" when a.type = :type_surcharge and a.amountType = :amount_type_amount then ( a.amount ) " +
" when a.type = :type_discount and a.amountType = :amount_type_percentage then ( -1 * a.amount * qi.price ) " +
" else ( -1 * a.amount ) end ) + sum(qi.price) " +
" from " + Quote.class.getName() + " q " +
" left join q.quoteItems qi " +
" left join qi.adjustments a " +
" where q.date between :from and :to and q.contact.parent.region in :regions group by q.user, q.contact.parent.region";
问题是,如果报价项目具有多个调整项,则该项目在sum(qi.price)计算中会多次出现
谁能帮我解决此查询,使每个报价项只包括一次? ( sum( distinct qi.price )
不起作用)我希望可以在单个查询中完成。
编辑:这比我想象的要错误的多-即使存在使用左联接(?)的查询,如果存在没有调整的引号,查询的总和将返回null。 唯一正确的数据是:-对一项进行0或1项调整-通过区域/用户/期间过滤器的所有报价中至少对一项进行调整。
实体(简体)
@Entity
@DiscriminatorValue(AbstractCollateral.TYPE_QUOTE)
@Table(name="customer_quote", uniqueConstraints={@UniqueConstraint(name="quote_number_uk", columnNames={"number"})})
public class Quote extends AbstractCollateral<QuotedCarePack>
{
... other elements
@OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval=true)
protected Set<QuotedCarePack> quoteItems;
}
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="collateral_type", discriminatorType=DiscriminatorType.STRING, length=10)
@Table(name="abstract_collateral")
public abstract class AbstractCollateral<T extends AbstractCollateralItem<?>> extends AbstractManagedData implements ContactInfo{
private static final long serialVersionUID = 1L;
public static final String TYPE_ORDER = "order";
public static final String TYPE_QUOTE = "quote";
@Column(name="collateral_type", insertable=true, updatable=false, length=10)
protected String collateralType;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="customer_contact_id", nullable=false)
protected CustomerContact contact;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="user_id", nullable=false)
protected User user;
/**
* The date the collateral was made (not the sent date, necessarily)
*/
@Column(name="creation_date", nullable=false)
@Temporal(TemporalType.TIMESTAMP)
protected Date date;
}
@Entity(name="quoted_care_pack")
public class QuotedCarePack extends AbstractCollateralItem<Quote> {
private static final long serialVersionUID = 1L;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="quote_id", nullable=false)
protected Quote parent;
@OneToMany(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable
(
name="quoted_care_pack_adjustment",
joinColumns={ @JoinColumn(name="quoted_care_pack_id", referencedColumnName="id") },
inverseJoinColumns={ @JoinColumn(name="adjustment_id", referencedColumnName="id", unique=true) }
)
protected Set<Adjustment> adjustments;
}
@Entity(name="adjustment")
public class Adjustment extends AbstractManagedData {
private static final long serialVersionUID = 1L;
@Column(name="amount")
protected double amount;
@Column(name="reason", length=100)
protected String reason;
@Column(name="type")
@Enumerated(EnumType.STRING)
protected AdjustmentType type;
@Column(name="amount_type")
@Enumerated(EnumType.STRING)
protected AdjustmentAmountType amountType;
}
不幸的是,JPA不支持select子句中的子查询,这是您需要执行的操作,以使获得所有调整总和的联接不会影响quoteItems的总和。
这样就可以使用本机SQL,或者执行两个查询-一个用于qi.price和,另一个用于调整和:
"select q.user, q.contact.parent.region, sum(qi.price) " +
" from " + Quote.class.getName() + " q " +
" left join q.quoteItems qi " +
" where q.date between :from and :to and q.contact.parent.region in :regions group by q.user, q.contact.parent.region";
和
"select q.user, q.contact.parent.region, sum( case " +
" when a.type = :type_surcharge and a.amountType = :amount_type_percentage then ( a.amount * qi.price ) " +
" when a.type = :type_surcharge and a.amountType = :amount_type_amount then ( a.amount ) " +
" when a.type = :type_discount and a.amountType = :amount_type_percentage then ( -1 * a.amount * qi.price ) " +
" else ( -1 * a.amount ) end ) " +
" from " + Quote.class.getName() + " q " +
" left join q.quoteItems qi " +
" left join qi.adjustments a " +
" where q.date between :from and :to and q.contact.parent.region in :regions group by q.user, q.contact.parent.region";
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.