如何在 JPQL 中正确执行 LIKE 和 CASE 子句

Posted

技术标签:

【中文标题】如何在 JPQL 中正确执行 LIKE 和 CASE 子句【英文标题】:How to properly execute LIKE and CASE clause in JPQL 【发布时间】:2021-09-09 05:59:22 【问题描述】:

我想执行一个在 sql 中工作的查询,但是当我尝试使用 @Query 注释运行它时,程序就死了,我正在尝试将字符串与子字符串进行比较,但我不知道该怎么做做。我已经尝试了很长时间来弄清楚如何解决这些问题。

package stpt.Repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import stpt.entities.StopTimes;

import java.util.Date;
import java.util.List;

public interface StopTimesRepository extends JpaRepository<StopTimes,String> 
  @Query("SELECT arrivalTime FROM StopTimes st WHERE tripId IN (:id)")
  List<String> findBySpecificTime(@Param("id") String id);
  @Query("SELECT distinct st.arrivalTime \n" +
          "FROM StopTimes st, Trips t, Routes r, Stops s \n" +
          "WHERE r.routeShortName IN (:short_name)\n" +
          "AND t.tripHeadsign IN (:heading)\n" +
          "AND st.tripId=t.tripId\n" +
          "AND t.routeId=r.routeId \n" +
          "AND s.stopId=st.stopId\n" +
          "AND CASE WHEN dayname(current_date())='saturday' OR dayname(current_date())='sunday' THEN t.serviceId like '%-sd' else t.serviceId like '%-lv' END\n" +
          "AND CASE HOUR(current_time())=11 THEN st.arrivalTime LIKE '23%' else st.arrivalTime LIKE '23%' END\n" +
          "AND s.stopName IN (:stop)")
  List<String> findByArrivalTime(@Param("short_name") String short_name, @Param("heading") String heading, @Param("stop") String stop);

st<String> findByArrivalTime(@Param("short_name") String short_name, @Param("heading") String heading, @Param("stop") String stop);


以及来自控制台的主要错误:

2021-06-26 01:51:45.744 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 8:103: unexpected token: like
2021-06-26 01:51:45.751 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 8:103: unexpected token: like

antlr.NoViableAltException: unexpected token: like

at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.3.jar:2.4.3]

2021-06-26 01:51:45.753 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 8:115: unexpected token: else
2021-06-26 01:51:45.754 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 8:115: unexpected token: else

antlr.NoViableAltException: unexpected token: else

at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.3.jar:2.4.3]

2021-06-26 01:51:45.756  WARN 12100 --- [  restartedMain] o.hibernate.hql.internal.ast.HqlParser   : HHH000203: processEqualityExpression() : No expression to process!
2021-06-26 01:51:45.757 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 8:120: unexpected token: t
2021-06-26 01:51:45.760 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 8:120: unexpected token: t

antlr.NoViableAltException: unexpected token: t

at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.3.jar:2.4.3]

2021-06-26 01:51:45.763 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 9:28: expecting EOF, found ')'
2021-06-26 01:51:45.765 ERROR 12100 --- [  restartedMain] o.h.hql.internal.ast.ErrorTracker        : line 9:28: expecting EOF, found ')'

antlr.MismatchedTokenException: expecting EOF, found ')'
   at antlr.Parser.match(Parser.java:211) ~[antlr-2.7.7.jar:na]

at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.4.3.jar:2.4.3]

2021-06-26 01:51:45.785  WARN 12100 --- [  restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'appController': Unsatisfied dependency expressed through field 'services'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'services': Unsatisfied dependency expressed through field 'stopTimesRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stopTimesRepository' defined in stpt.Repository.StopTimesRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List stpt.Repository.StopTimesRepository.findByArrivalTime(java.lang.String,java.lang.String,java.lang.String)!

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-06-26 01:51:45.892 ERROR 12100 --- [  restartedMain] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'appController': Unsatisfied dependency expressed through field 'services'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'services': Unsatisfied dependency expressed through field 'stopTimesRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stopTimesRepository' defined in stpt.Repository.StopTimesRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Validation failed for query for method public abstract java.util.List stpt.Repository.StopTimesRepository.findByArrivalTime(java.lang.String,java.lang.String,java.lang.String)!

Caused by: java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: like near line 8, column 103 [SELECT distinct st.arrivalTime 
FROM stpt.entities.StopTimes st, stpt.entities.Trips t, stpt.entities.Routes r, stpt.entities.Stops s 
WHERE r.routeShortName IN (:short_name)
AND t.tripHeadsign IN (:heading)
AND st.tripId=t.tripId
AND t.routeId=r.routeId 
AND s.stopId=st.stopId
AND CASE WHEN dayname(current_date())='saturday' OR dayname(current_date())='sunday' THEN t.serviceId like '%-sd' else t.serviceId like '%-lv' END
AND CASE HOUR(current_time())=11 THEN st.arrivalTime LIKE '23%' else st.arrivalTime LIKE '23%' END
AND s.stopName IN (:stop)]

Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token: like near line 8, column 103 [SELECT distinct st.arrivalTime 
FROM stpt.entities.StopTimes st, stpt.entities.Trips t, stpt.entities.Routes r, stpt.entities.Stops s 
WHERE r.routeShortName IN (:short_name)
AND t.tripHeadsign IN (:heading)
AND st.tripId=t.tripId
AND t.routeId=r.routeId 
AND s.stopId=st.stopId
AND CASE WHEN dayname(current_date())='saturday' OR dayname(current_date())='sunday' THEN t.serviceId like '%-sd' else t.serviceId like '%-lv' END
AND CASE HOUR(current_time())=11 THEN st.arrivalTime LIKE '23%' else st.arrivalTime LIKE '23%' END
AND s.stopName IN (:stop)]

【问题讨论】:

您将WHERE tripId IN (:id)@Param("id") String id 一起使用,与其他参数类似。对于IN,您应该使用参数作为集合,例如WHERE tripId IN (:ids)@Param("ids") Set&lt;String&gt; ids。另外,尽量简化你的sql查询,以便更快地找到有问题的地方(仅出于调试目的,尝试删除where子句的某些部分) 【参考方案1】:

我通过将 nativequery 切换为 true 来解决它,从而允许使用简单的 sql。

@Query(value = "SELECT distinct arrival_time, stop_name\n" +
            "FROM stop_times st, trips t, routes r, stops s \n" +
            "WHERE r.route_short_name=:short_name\n" +
            "AND t.trip_headsign=:heading\n" +
            "AND st.trip_id=t.trip_id\n" +
            "AND t.route_id=r.route_id \n" +
            "AND s.stop_id=st.stop_id\n" +
            "AND IF(DAYOFWEEK(CURDATE())=7 OR DAYOFWEEK(CURDATE())=1, t.service_id LIKE '%-sd', t.service_id LIKE '%-lv')\n" +
            "AND IF(HOUR(CURTIME())=23, st.arrival_time LIKE '23:%',23)\n" +
            "AND s.stop_name=:stop",nativeQuery = true)
    List<String> findByArrivalTime(@Param("short_name") String short_name, @Param("heading") String heading, @Param("stop") String stop);

【讨论】:

以上是关于如何在 JPQL 中正确执行 LIKE 和 CASE 子句的主要内容,如果未能解决你的问题,请参考以下文章

使用多个 ID 时在 JPQL 中执行 CRUD 操作的正确方法是啥

如何在 JPQL(Spring JPA 查询)中使用 JOIN 执行 UPDATE 语句?

在 JPQL 中将整数转换为字符串

如何使用 Hibernate 5 正确创建 JPQL 查询(不推荐使用查询类型)

类似子句 JPQL 中的参数

JPQL模糊匹配单个字符