QueryDsl按星期几汇总为地图

问题描述

我想按星期几的类型获取预订数量,例如:

| 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())));

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...