簡體   English   中英

如何使JPQL加入不能使結果翻倍

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM