问题描述
| DoW | Type | Count |
|----- |--------|-------|
| 1 | Store | 3 |
| 1 | Remove | 2 |
结果应为Map<Integer,Map<String,Long>>
。我已经尝试了一些变化:
LocalDateTime monday = LocalDate.Now().with(DayOfWeek.MONDAY).atStartOfDay();
LocalDateTime nextMonday = monday.plusDays(7);
var dayOfWeek = booking.bookingDate.dayOfWeek().subtract(1);
new JPAQuery<>(entityManager)
.select(dayOfWeek,booking.bookingType,booking.bookingType.count())
.from(booking)
.where(booking.bookingDate.between(monday,nextMonday))
.groupBy(booking.bookingDate,booking.bookingType)
.transform(groupBy(dayOfWeek)
.as(map(booking.bookingType,booking.bookingType.count())));
尽管它没有给我正确的计数(所有1)。我考虑过将dayofweek
放在groupby子句bc中。我担心按LocalDateTime分组时,“时间”部分会弄乱事情,但这没用。
此postgreSQL查询按预期工作:
select
extract(DOW from b.book_date)-1 as dow,b.dtype as type,count(b.dtype) as cnt
from
booking b
where
b.book_date between '2020-05-11 0:0:0.000000' and '2020-05-18 0:0:0.000000'
group by
b.book_date,b.dtype
编辑:
将“ dayOfWeek”添加到groupBy子句时,如下所示:
.groupBy(dayOfWeek,buchung.buchungType)
然后我得到一个例外:
javax.persistence.PersistenceException: org.hibernate.exception.sqlGrammarException: Could not extract ResultSet
[...]
Caused by: org.h2.jdbc.JdbcsqlSyntaxErrorException: Feld
"BOOKING0_.BOOKING_DATE" muss in der GROUP BY Liste sein
Column "BOOKING0_.BOOKING_DATE" must be in the GROUP BY list; sql statement:
/* select dayofweek(booking.gebuchtDate) - ?1,count(booking.bookingType)
from Buchung booking
where booking.bookingDate between ?2 and ?3
group by dayofweek(booking.gebuchtDate) - ?1,booking.bookingType */ select dayofweek(booking0_.booking_date)-? as col_0_0_,booking0_.dtype as col_1_0_,count(booking0_.dtype) as col_2_0_ from booking booking0_ where booking0_.booking_date between ? and ? group by dayofweek(booking0_.booking_date)-?,booking0_.dtype [90016-200]
编辑2:
Jan-Willem Gmelig Meyling的以下问题解决了该查询,但是我将“星期几”从“周六”转换为“周一至周日”的逻辑当然是垃圾。让我们看一下:
Postgresql将星期日(0)返回到星期六(6)(这似乎是ISO sql方式),而java.time将ISO-8601标准格式从星期一(1)返回到星期日( 7)。因此,除了星期天,基本上所有内容都匹配。
更糟糕的是,我读到您可以在MS sql上更改一周的开始日期。
由于我不想为此烦恼,所以将其更改为“年度”,并且正在使用Java进行转换。由于结果集最多包含7个条目,所以还不错:
var dayOfYear = booking.bookingDate.dayOfYear();
var res = new JPAQuery<>(entityManager)
.from(booking)
.where(booking.bookingDate.between(monday,nextMonday))
.groupBy(dayOfYear,booking.bookingType)
.transform(groupBy(dayOfYear)
.as(map(booking.bookingType,booking.bookingType.count())));
return res.entrySet().stream()
.collect(toMap(
e -> Year.Now().atDay(e.getKey()).getDayOfWeek().getValue(),Map.Entry::getValue
));
解决方法
参数“ 1”被参数化,结果在查询执行计划时,按表达式分组的表达式与选择表达式不相等。您必须为1使用常数。 .subtact(Expressions.numberTemplate(Integer.class,"1"))
。
此外,我相信QueryDSL会在DayOfWeek中添加1,以使其与Java的“星期几”保持一致,而不是与ANSI SQL中定义的DayOfWeek保持一致。您可以考虑使用JPQLTemplates
的自定义实例,该实例为DAY_OF_WEEK
运算符定义了一个不同的标准模板(并在其中呈现常量)。在您的应用程序中,这可能是更安全的默认设置。
或者,当使用Hibernate 5.4.10或更高版本时,也可以使用“别名分组”:在选择表达式中使用dayOfWeek.as("dayOfWeekAlias")
,然后在group by子句中使用Expressions.numberPath(Integer.class,"dayOfWeekAlias")
: / p>
new JPAQuery<>(entityManager)
.from(booking)
.where(booking.bookingDate.between(monday,nextMonday))
.groupBy(Expressions.numberPath(Integer.class,"dayOfWeekAlias"),booking.bookingType)
.transform(groupBy(dayOfWeek).as("dayOfWeekAlias")
.as(map(booking.bookingType,booking.bookingType.count())));