在 JPA 查询中,如何传递值列表并获取表中不存在的 id?

问题描述 投票:0回答:2

我有一个名为“employee”的表,其中 id 作为列。我想通过提供 ids 列表来查询数据库,并仅获取数据库中不存在的 id。我试过了

@Query(value = "select id from (VALUES(:ids)) v(id) except (select id from employee)",
            nativeQuery = true)
    public List<String> filterNonExistingEmployeeiIds(@Param("ids") List<String> ids);

我尝试使用本机查询和值(:ids)进行传递。它只选择一个 id,而不是列表中所有传递的 id。有什么方法可以选择列表中的所有值。

postgresql jpa spring-data-jpa
2个回答
0
投票

我认为 Postgres 的 SQL 应该是这样的

select *
from unnest(array['id1','id2','id3', ...]) as t(id)
where id not in (select e.id from Employee as e);

我认为你不能用 JPA 或 HQL 编写这个(至少使用 Hibernate ORM 5),而且我不确定你是否可以使用参数。

但是,你可以尝试这个:

@Query(
    value = "select * from unnest(array[:ids]) as t(id) where id not in (select id from Employee as e)",
    native=true)
public List<String> filterNonExistingEmployeeiIds(@Param("ids") List<String> ids);

或者您可以创建一个表示 ids 列表的字符串和

string_to_array
:

@Query(
    value="select * from unnest(string_to_array(:ids, ',')) as t(id) where id not in (select e.id from Employee as e)",
    native=true)
public List<String> filterNonExistingEmployeeiIds(@Param("ids") String ids);
...

List<String> ids = ...
String idsAsString = ids.stream().collect(Collectors.joining(",");
List<String> nonExistingIds = repository.filterNonExistingEmployeeiIds(idsAsString);

如果这两种方法都不起作用,您可以自己创建查询字符串并使用自定义存储库:

public class CustomRepositoryImpl implements CustomRepository {
     
    @PersistenceContext
    private EntityManager entityManager;
 
    @Override
    public List<String> filterNonExistingEmployeeiIds(List<String> ids) {
        String query = ... // create the query 
        return entityManager.createNativeQuery(query, String.class).getResultList();
    }
}

0
投票

它只选择一个 id,而不是列表中所有传递的 id。有什么方法可以选择列表中的所有值吗?

是的,它至少可以在反应式本机查询中工作

org.springframework.data.r2dbc.repository.Query
,但我相信它也可以在标准 JPA 中工作。

有两点:

  1. 占位符周围不能有括号,因此必须是
    (VALUES :ids)
    而不是
    (VALUES (:ids))
@Query("select * from (VALUES :ids) as v(id)...")
  1. 通过将每个元素包装在另一个数组中,强制每个 ID 周围使用内括号
    (VALUES (id1), (id2), (id3), ...)
    ,因此传递
    Collection<Object[]> ids
    而不是
    Collection<String> ids
/** The internal implementation */
@Query("select * from (VALUES :ids) as v(id)...")
List<String> getMyValuesImpl(Collection<Object[]> ids);

/** The method with a nice signature */
default List<String> getMyValues(Collection<String> ids) {
    return getMyValuesImpl(ids.stream().map(id -> new Object[]{id}).toList());
}
© www.soinside.com 2019 - 2024. All rights reserved.