我有一堂课,里面有地图。
@Entity
public class Purchase {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer purchaseId;
@ManyToOne
@JoinColumn(name = "customer_id")
private User customer;
@ManyToOne
@JoinColumn(name = "item_id")
private Item item;
private String customization;
@ElementCollection
@MapKeyEnumerated(value = EnumType.STRING)
@CollectionTable(name = "purchase_status")
@MapKeyColumn(name = "status")
@Column(name = "date")
private Map<PurchaseStatus, Date> statusTransitions = new HashMap<>();
private Date expectedDeliveryDate;
@ManyToOne
@JoinColumn(name = "purchase_cart_id")
@JsonIgnore
private PurchaseCart purchaseCart;
@OneToOne
@JoinColumn(name = "destination_address_id")
private DestinationAddress destinationAddress;
@Transient
@JsonIgnore
private Date purchaseDate;
代表购买。 PurchaseStatus是一个枚举器。 statusTransitions代表此购买获得的所有状态。特别是可以是“ READY_TO_BE_PAID”和“ PAID”。状态具有它的相对日期,即地图的VALUE,状态本身就是地图的KEY,因为购买只能处于一次精确的状态。 我想从数据库中获取所有带有特定用户(用户名,这是用户的属性)的购买,以及statusTransitions HashMap中具有特定(键,值)对的所有购买。 特别是,我想创建一个查询,该查询返回日期(VALUE)在两个日期(fromDate和toDate)之间且PurchaseStatus(KEY)等于枚举值“ READY_TO_BE_PAID”的所有购买。
我创建了这个自定义查询:
@Query("select p from Purchase p JOIN p.customer c JOIN p.statusTransitions s WHERE c.username = :username and " +
"(KEY(s) = 'READY_TO_BE_PAID' and " +
"VALUE(s) >= :fromDate and " +
"VALUE(s) <= :toDate)")
List<Purchase> findByUsernameAndByDate(@Param("fromDate") Date fromDate, @Param("toDate") Date toDate, @Param("username") String username);
唯一的问题是生成的SQL查询如下:
select
*
from
purchase purchase0_
inner join user user1_ on purchase0_.customer_id=user1_.user_id
inner join purchase_status statustran2_ on purchase0_.purchase_id=statustran2_.purchase_purchase_id
where
statustran2_.status='READY_TO_BE_PAID' and
user1_.username=? and
(select
statustran2_.date
from
purchase_status statustran2_
where
purchase0_.purchase_id=statustran2_.purchase_purchase_id
)>=? and
(select
statustran2_.date
from
purchase_status statustran2_
where
purchase0_.purchase_id=statustran2_.purchase_purchase_id
)<=?
这不是我想要的。它生成两个子查询,结果是抛出此错误:
java.sql.SQLException: Subquery returns more than 1 row
那是因为当它执行子查询时,它不会过滤PurchaseStatus上的行,而是以这种方式返回多行。 关键是我不知道如何重写查询以避免这两个子查询或将WHERE子句放入此(KEY(s)='READY_TO_BE_PAID')条件。我发现其他人也遇到同样的问题,但找不到任何解决方案。
答案 0 :(得分:0)
我找到了解决方案!看来,当您有此查询
SELECT p
FROM Purchase p
JOIN p.customer c
JOIN p.statusTransitions s
statusTransactions映射的别名“ s”已经是值,而不是使您相信的对(键,值)。这有点直观,因为KEY返回键,但是VALUE不返回值,而是自动生成一个子查询,这不可避免地导致您出错。
java.sql.SQLException: Subquery returns more than 1 row
所以重写它的正确方法是:
SELECT p
FROM Purchase p
JOIN p.customer c
JOIN p.statusTransitions s
WHERE
c.username = :username and
KEY(s) = 'READY_TO_BE_PAID' and
VALUE(s) >= :fromDate and
VALUE(s) <= :toDate
是:
SELECT p
FROM Purchase p
JOIN p.customer c
JOIN p.statusTransitions s
WHERE
c.username = :username and
KEY(s) = 'READY_TO_BE_PAID' and
s >= :fromDate and
s <= :toDate
或更紧凑:
SELECT p
FROM Purchase p
JOIN p.customer c
JOIN p.statusTransitions s
WHERE
c.username = :username and
KEY(s) = 'READY_TO_BE_PAID' and
s BETWEEN :fromDate and :toDate
正如我已经说过的,别名“ s”已经是(键,值)对的值!