JPQL中like子句中的参数

106

我正在尝试编写带有like子句的JPQL查询:

LIKE '%:code%'

我想要code=4并找到它

455
554
646
...

我无法通过:code = '%value%'

namedQuery.setParameter("%" + this.value + "%");

因为在另一个地方我需要:value而不是被%字符包裹。有什么帮助吗?


2
@Manuele Piastra:下面的答案不是你想要的吗? - wmorrison365
9个回答

177
如果你这样做:
LIKE :code

然后执行

namedQuery.setParameter("code", "%" + this.value + "%");

然后该值将不包含'%'符号。如果您需要在同一查询中的其他地方使用它,请使用不同于'code'的其他参数名称。


10
记录一下,这不会让您容易受到JPQL注入攻击,因为this.value已经被自动适当地转义了。 - László van den Hoek
4
这个 "%" + this.value + "%" 是被转义的内容。 - Gustavo
2
如何使此不区分大小写? - EM-Creations
就像Gustavo之前注意到的那样,"%...%"是被转义的部分。因此,在LIKE子句中,模式应该不是%...%,而是%...%,这是错误的。所以,这不是一个正确的答案。我错过了什么? - undefined

63

我不会在所有查询中使用命名参数。例如,在JpaRepository中使用命名参数是不寻常的。

为了解决这个问题,我使用JPQL的 CONCAT 函数(此代码模拟start with):

@Repository
public interface BranchRepository extends JpaRepository<Branch, String> {
    private static final String QUERY = "select b from Branch b"
       + " left join b.filial f"
       + " where f.id = ?1 and b.id like CONCAT(?2, '%')";
    @Query(QUERY)
    List<Branch> findByFilialAndBranchLike(String filialId, String branchCode);
}

我在优秀的文档中发现了这个技术:http://openjpa.apache.org/builds/1.0.1/apache-openjpa-1.0.1/docs/manual/jpa_overview_query.html


3
注意:CONCAT(?2,'%')将在参数末尾添加'%',使用CONCAT('%',?2,'%')将其添加到参数的开头和结尾。 - Muizz Mahdy
1
补充上面的评论,Oracle中的语法是:CONCAT(CONCAT('%', ?2), '%'),用于在字符串的开头和结尾添加%。 - jbaranski
Oracle?这不是一个本地查询,对吗? - undefined
JPQL支持许多函数。它们被翻译为RDBMS的本地功能。获取JPA 2.2的规范PDF:JSR 338,第4.6.17.2节 内置字符串、算术和日期时间函数表达式 - undefined

8
你可以使用JPA LOCATE函数

LOCATE(searchString, candidateString [, startIndex]):返回candidateString中searchString的第一个索引。 索引基于1。如果未找到字符串,则返回0。

FYI:在我查到的谷歌搜索结果上,参数被颠倒了。
SELECT 
  e
FROM 
  entity e
WHERE
  (0 < LOCATE(:searchStr, e.property))

1
对我来说,最好的解决方案是——没有字符串连接,也没有 SQL 注入。 - hgoebl
如果 :searchStr 实际上是一个列表,有没有办法使用 LOCATE 函数来查找它? - Danilo Körber
MySQL的文本查询是不区分大小写的(基于字段的排序规则),因此实际上可以执行不区分大小写的查询,而无需使用LOWER()等方式对性能和可读性产生影响。 - E-Riz
MySQL文本查询是不区分大小写的(基于字段的排序规则),因此实际上执行了不区分大小写的查询,而不会影响性能和可读性,比如LOWER()这样的函数。 - undefined

4

JPA标准API中有一个很好用的like()方法。尝试使用它,希望能帮到你。

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery criteriaQuery = cb.createQuery(Employees.class);
Root<Employees> rootOfQuery = criteriaQuery.from(Employees.class);
criteriaQuery.select(rootOfQuery).where(cb.like(rootOfQuery.get("firstName"), "H%"));

3

我不知道是否已经太晚或者超出范围,但是我认为我可以这样做:


(以下内容涉及IT技术,翻译可能有些专业术语,请您谅解)

String orgName = "anyParamValue";

Query q = em.createQuery("Select O from Organization O where O.orgName LIKE '%:orgName%'");

q.setParameter("orgName", orgName);

3

使用JpaRepositoryCrudRepository作为存储库接口:

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {

    @Query("SELECT t from Customer t where LOWER(t.name) LIKE %:name%")
    public List<Customer> findByName(@Param("name") String name);

}


@Service(value="customerService")
public class CustomerServiceImpl implements CustomerService {

    private CustomerRepository customerRepository;
    
    //...

    @Override
    public List<Customer> pattern(String text) throws Exception {
        return customerRepository.findByName(text.toLowerCase());
    }
}

3
使用以下JPQL查询语句。
select i from Instructor i where i.address LIKE CONCAT('%',:address ,'%')");

请使用以下标准代码:
  1. 使用以下标准代码:
@Test
public void findAllHavingAddressLike() {
    CriteriaBuilder cb = criteriaUtils.criteriaBuilder();
    CriteriaQuery<Instructor> cq = cb.createQuery(Instructor.class);
    Root<Instructor> root = cq.from(Instructor.class);
    printResultList(cq.select(root).where(
        cb.like(root.get(Instructor_.address), "%#1074%")));
}

1
只需省略''即可。
LIKE %:code%

踩一下:不起作用,这会将参数名称更改为code%。 - kaiser
这个答案非常错误和误导,你不能在JPA查询中这样做。 - Remy
1
Spring Data似乎接受这种语法(在@Query注释中),而JPQL则不接受。 - TXN
哇,这对我起作用了,不知道为什么,看起来很糟糕,但在使用Spring数据时,当单引号使查询返回null时,它确实有效。 - snakedog

0

使用JPQL查询。

@Query("select e from Entity e where e.id = ?1 and e.code like CONCAT('%', CONCAT(?2, '%'))")
List<Entity> findByIdAndCodeLike(Long id, String code);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接