将List <string>传递给postgres的函数作为参数

时间:2019-03-14 18:35:41

标签: java postgresql spring-data-jpa spring-data plpgsql

我有这样的spring数据存储库界面:

public interface MyEntityRepository extends 
        JpaRepository<MyEntity, Long> {

    @Query(nativeQuery = true, value = "select * from my_func(:myList)")
    Page<MyEntity> findBy(
            @NonNull @Param("myList") List<String> myList,
            @NonNull Pageable pageable);

}

我已经这样定义了Postgres的函数(但是如果做错了我可以更改它):

CREATE OR REPLACE FUNCTION my_func(variadic myList text[])
RETURNS SETOF myEntityTable AS $$
... some logic
select * from myEntityTable t where t.foo in (myList);

当我调用此存储库方法时,出现此错误:

ERROR: operator does not exist: character varying = text[]
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Where: PL/pgSQL function f_najdi_autorizaciu_na_spracovanie(text[]) line 28 at RETURN QUERY

能否请您告诉我在postgres函数中应该使用哪种类型?谢谢你的建议。

编辑: 我不能在存储库方法上方使用本机查询,而不能将那里的列表传递到IN子句中,因为我在DB函数中具有更多的逻辑,变量等……它必须是DB函数。

2 个答案:

答案 0 :(得分:1)

在类似情况下,我使用了以下变通办法:

1)创建了两个助手功能:

-- Convert a variable number of text arguments to text array
-- Used to convert Java collection to the text array
--
create or replace function list_to_array(variadic _list text[]) returns text[] language sql as $$
select _list;
$$;
-- Convert the bytea argument to null.
-- Used to convert Java null to PostgreSQL null
--
create or replace function list_to_array(_list bytea) returns text[] language sql as $$
select null::text[];
$$;

2)在主要功能中使用any代替in,例如:

create or replace function my_func(_params text[]) 
returns table (field1 text, field2 text) 
language sql as 
$$
select
  t.field1 as field1,
  t.field2 as field2,
from
  my_table t
where
  array_length(_params, 1) is null or t.foo = any(_params);
$$;

3)然后在存储库方法中使用它们,例如:

@NonNull
@Query(value = "select ... from my_func(list_to_array(?1))", nativeQuery = true)
List<MyProjection> getFromMyFunc(@Nullable Set<String> params, @NonNull Pageable page);

答案 1 :(得分:0)

恐怕我不知道如何使用Spring Data JPA做到这一点,但是对于普通的JDBC,您只需将绑定变量强制转换为text[]并传递一个String[]输入而不是列表。例如:

try (PreparedStatement s = conn.prepareStatement("select * from my_func(?::text[])")) {
    s.setObject(1, myList.toArray(new String[0]));

    try (ResultSet rs = s.executeQuery()) {
        // ...
    }
}

此处的关键信息是JDBC驱动程序将使用数组,而不是列表。