JPA μ§κ³ν¨μ sum μ long μ λ°ννλ€.
μ΅κ·Ό λλμ λ°μ΄ν°λ€μ μ§κ³νμ¬ μ‘°ννλ API νλ‘μ νΈλ₯Ό μ§ν μ€μ,
Spring Data JPA μ Querydsl μ μ΄μ©νμ¬ μΏΌλ¦¬λ₯Ό μμ±νκ³ μμλ€.
μ€λ, sum μ§κ³ ν¨μ λλ¬Έμ, java object λ‘ λ§€νμ΄ μλλ λ¬Έμ κ° μμλλ°,
κ·Έ μ΄μ μ ν΄κ²°κ³Όμ μ μ€λͺ ν΄λ³΄κ² λ€.
기쑴 쿼리
@Query(
"""
select
new service.dto.PaymentTotalSumDTO(
sum(sub.totalAmount) as totalAmount,
sum(sub.discount) as discount,
sum(sub.usedPoint) as usedPoint
)
from
(select
tpd.totalAmount as totalAmount,
tpd.discount as discount,
tpd.usedPoint as usedPoint,
from TransactionPaymentDetail tpd
where tpd.sid = :sid
group by
tpd.pid,
tpd.totalAmount,
tpd.discount,
tpd.usedPoint) sub
"""
)
fun findTotalSumBySid(
sid: String
): PaymentTotalSumDTO?
data class PaymentTotalSumDTO(
val totalAmount: BigDecimal = BigDecimal.ZERO,
val discount: BigDecimal = BigDecimal.ZERO,
val usedPoint: BigDecimal = BigDecimal.ZERO,
)
JPQL λ‘ groupby νμ¬ μ»μ μλΈμΏΌλ¦¬μμ κ° μ»¬λΌλ³λ‘ sum μ λλ € DTO λ‘ μ‘°ννλ ν¨μμ΄λ€.
ν΄λΉ query λ μ΄λ¬ν μλ¬λ₯Ό λ°μμν€λ©°, μ€ν¨νλ€.
Caused by: java.lang.IllegalArgumentException: org.hibernate.QueryException: Function argument [SqmBasicValuedSimplePath(<<derived>>(sub).totalAmount)] of type [org.hibernate.query.derived.AnonymousTupleSqmPathSource@59282e4a] at specified position [1] in call arguments was not typed as an allowable function return type
at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:141)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:374)
at org.hibernate.query.sq m.internal.QuerySqmImpl.list(QuerySqmImpl.java:1073)
at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:457)
at org.hibernate.query.sqm.internal.QuerySqmImpl.getSingleResult(QuerySqmImpl.java:1103)
무μμ΄ λ¬Έμ μμκΉ?
- νμ΄λ²λ€μ΄νΈμ μ§κ³ν¨μ sum μ long νμ μ λ°ννλ€.
BigDecimal νμ κ³Ό Long νμ μ΄ μΌμΉνμ§ μμ, object λ‘ λ§€νμ΄ λμ§ μλ κ²μ΄λ€.
μ΄λ»κ² ν΄μΌ ν κΉ?
@Query(
"""
select
new service.dto.PaymentTotalSumDTO(
sum(cast(sub.totalAmount as bigdecimal)) as ta,
sum(cast(sub.discount as bigdecimal)) as discount,
sum(cast(sub.usedPoint as bigdecimal)) as usedPoint
)
from
(select
tpd.totalAmount as totalAmount,
tpd.discount as discount,
tpd.usedPoint as usedPoint,
from TransactionPaymentDetail tpd
where tpd.sid = :sid
group by
tpd.pid,
tpd.totalAmount,
tpd.discount,
tpd.usedPoint) sub
"""
)
fun findTotalSumBySid(
sid: String
): PaymentTotalSumDTO?
- cast ν¨μλ₯Ό μ΄μ©νμ¬ bigdecimal νμ μΌλ‘ μΊμ€ν ν΄μ£Όμλ€.
μλΈ μΏΌλ¦¬μΈ sub λ μ€νμμ μ entity μ λͺ μλ νμ λλ‘ bigdecimal νμ μ λ°ννμ§λ§,
sub λ₯Ό μ΄μ©νμ¬ select νλ ꡬκ°μμ νμ΄λ²λ€μ΄νΈλ type μ μ©μ΄ λμ§ μμλ²λ¦°λ€.
DB λ¨μμ νλ²μ 쿼리νλ κ²μ΄ μλ, μ ν리μΌμ΄μ λ©λͺ¨λ¦¬μμ long μ λ°ννλ sum ν¨μκ° μ€νλκΈ° λλ¬Έμ΄λ€.
κ·ΈλΌ μ μμ μΌλ‘ μΏΌλ¦¬κ° μ€νλλ κ²μ μ μ μλ€.
According to the JPA spec 4.5.8
The Java type that is contained in the result of a query using an aggregate function is as follows:
• COUNT returns Long.
• MAX, MIN return the type of the state field to which they are applied.
• AVG returns Double.
• SUM returns Long when applied to state fields of integral types (other than BigInteger); Double when applied to state fields of floating point types; BigInteger when applied to state fields of type BigInteger; and BigDecimal when applied to state fields of type BigDecimal.
μ°Έμ‘° :
https://stackoverflow.com/questions/61954687/jpa-sum-returns-long