繁体   English   中英

查询结果为“错误:运算符不存在:字符变化 ~~ bytea”

[英]Query resulting into "ERROR: operator does not exist: character varying ~~ bytea"

我有一个查询,我需要首先检查输入参数是否为空或比较列值以传递输入参数。 这意味着列值可以为 null 或传递指定的条件(?3 is null or cd.name like %?3%)

public interface PageableCategoryRepository extends PagingAndSortingRepository<Category, Long> {
  @Query(
      value = "select distinct c from Category c left join fetch c.descriptions cd join fetch cd.language cdl join fetch c.merchantStore cm"
          + "  where cm.id=?1 and cdl.id=?2 and (?3 is null or cd.name like %?3%) order by c.lineage, c.sortOrder asc",
      countQuery = "select  count(c) from Category c join c.descriptions cd join c.merchantStore cm "
          + "where cm.id=?1 and cd.language.id=?2 and (?3 is null or cd.name like %?3%)")
  Page<Category> listByStore(Integer storeId, Integer languageId, String name, Pageable pageable);
}

上述查询因name属性中传递的空值而失败。 错误:

错误:运算符不存在:字符变化 ~~ bytea 提示:没有运算符匹配给定的名称和参数类型。 您可能需要添加显式类型转换。 职位:3259

我试图在谷歌以及 Stack Overflow 上搜索。 有许多类似的问题被问及回答。 但是这些解决方案都不适合我。

如果有人能提供一些见解或方向,我将不胜感激。

注意:Spring boot 版本 - 2.2.7.RELEASE,使用的 Postgresql 库版本 - 42.2.16,使用的 Postgresql 版本 - 12.4

如果参数为null ,则 Postgres 无法确定参数的类型。

这里已经讨论过这个问题: Spring Data Rest: "Date is null" query throws an postgres exception

建议的解决方案是显式转换参数(如错误消息中也建议的那样),或将参数包装在coalesce语句中。 所以这应该是诀窍:替换所有这些:

?3 is null 

通过这个声明:

coalesce(?3, null) is null

当涉及参数变化的查询时,查看 Criteria API 而不是使用@Query也是一个好主意,因为它允许非常动态地创建查询: https : @Query标准查询

最简单的解决方案是使用显式类型转换。 此外, LIKE的正确参数必须是字符串,因此用单引号括起来:

WHERE ... (?3::text IS NULL
           OR cd.name::text LIKE '%' || ?3::text || '%'
          )

如果您有可能在本机查询中使用空值,那么您必须直接使用 JPA 接口,而不是让 Spring 为您调用它们。 代替:

  @Query(
      value = "select distinct c from Category c left join fetch c.descriptions cd join fetch cd.language cdl join fetch c.merchantStore cm"
          + "  where cm.id=?1 and cdl.id=?2 and (?3 is null or cd.name like %?3%) order by c.lineage, c.sortOrder asc",
      countQuery = "select  count(c) from Category c join c.descriptions cd join c.merchantStore cm "
          + "where cm.id=?1 and cd.language.id=?2 and (?3 is null or cd.name like %?3%)")
  Page<Category> listByStore(Integer storeId, Integer languageId, String name, Pageable pageable);

你需要:

Page<Category> listByStore(Integer storeId, Integer languageId, String name, Pageable pageable) {
    EntityManager em = ...get from somewhere (maybe parameter?);
    TypedQuery<Category> q = (TypedQuery<Category>) em.createNativeQuery(..., Category.class);
    Integer exampleInt = 0;
    String exampleString = "";
    q.setParameter(1, exampleInt).setParameter(1, storeId);
    q.setParameter(2, exampleInt).setParameter(2, languageId);
    q.setParameter(3, exampleString).setParameter(3, name);
}

第一次调用setParameter告诉它类型,第二次调用setParameter实际值。

这背后的原因是 Postgres 在解析时确定类型,而 Hibernate 无法确定null的类型,因此在一个阶段假设它是java.io.Serializable ,然后告诉它在某个阶段假设bite[]后期。 这样做是出于与其他数据库的遗留兼容性原因,并且不太可能改变。 也许新的 Hibernate 6.0 类型系统会解决这个问题,但我没有跟上。 因此,当它告诉 Postgres 类型是bytea ,查询解析器找不到在 bytea 和给定的其他数据库类型之间注册的隐式类型转换器,因此会引发错误。

似乎使用命名参数而不是匿名参数使其工作。

就我而言,这不起作用:

@Query("""
    SELECT p FROM Participant p
    WHERE (?1 IS NULL OR p.firstName LIKE ?1)
    AND ?2 IS NULL OR e.id = ?2
    AND p.waitingList = ?3
    """)
List<Participant> findFiltered(String searchCriteria, Long eventId, boolean waitingList);

2021-07-05 10:13:39.768 WARN 28896 --- [XNIO-1 task-3] ohengine.jdbc.spi.SqlExceptionHelper:SQL 错误:0,SQLState:42883 2021-07-05 10:168:39。 28896 --- [XNIO-1 task-3] ohengine.jdbc.spi.SqlExceptionHelper:错误:运算符不存在:文本~~ bytea 提示:没有运算符匹配给定的名称和参数类型。 您可能需要添加显式类型转换。 职位 : 951

但是使用命名参数,它可以工作:

@Query("""
    SELECT p FROM Participant p
    WHERE (:searchCriteria IS NULL OR p.firstName LIKE :searchCriteria)
    AND :eventId IS NULL OR e.id = :eventId
    AND p.waitingList = :waitingList
    """)
List<Participant> findFiltered(@Param("searchCriteria") String searchCriteria, @Param("eventId") Long eventId, @Param("waitingList") boolean waitingList);

否则,如错误消息所述,显式转换也可以正常工作:

@Query("""
    SELECT p FROM Participant p
    WHERE (cast(?1 as text) IS NULL OR p.firstName LIKE cast(?1 as text))
    AND cast(?2 as long) IS NULL OR e.id = cast(?2 as long)
    AND p.waitingList = ?3
    """)
List<Participant> findFiltered(String searchCriteria, Long eventId, boolean waitingList);

对于可用的转换类型,请参阅https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#basic-provided

我使用 PostgreSQL 13。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM