如何在 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<String> 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 语句?