存储库 - 本机查询中的 order by 不起作用

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

我有一个 Spring Data JPA 存储库(在 postgres 数据库上),有时我需要使用 nativeQuery = true 选项来使用本机查询。

但是在我目前的情况下,我需要传递一个订单字段,并且这样做:

电话..

targetStatusHistoryRepository.findSirenAlarmTimeActivation([uuid,uuid2],"activation_name DESC", 0, 10)

.. 回购方法

@Query(
        nativeQuery = true,
        value = """select
                     a.name as activation_name,
                     min(transition_from_active_in_millis),
                     max(transition_from_active_in_millis),
                     avg(transition_from_active_in_millis) from target_status_history t, activation_scenario a
                     where t.activation_uuid=a.activation_scenario_id and t.transition_from_active_in_millis > 0 and t.activation_uuid in (:activationUUIDs) group by a.name,t.activation_uuid
                     order by :orderClause offset :offset limit :limit """
)
List<Object[]> findSirenAlarmTimeActivation(@Param("activationUUIDs") List<UUID> activationUUIDs,
                                                              @Param("orderClause") String orderClause, @Param("offset") int offset, @Param("limit") int limit )

我用 DESC 编写了一个单元测试,然后用 ASC 调用,反之亦然,似乎第一个调用是什么,第二个调用给出了相同的结果。

sql spring postgresql jpa native
5个回答
18
投票

如果这是一个准备好的语句,并且是在

ORDER BY
子句中提供的绑定值,那么这是有效的,但是...

提供的绑定值不会被解释为 SQL 文本。也就是说,该值将被视为只是一个值(如文字字符串)。它不会被视为列名称或

ASC
DESC
关键字。

在您的声明上下文中,为

:orderClause
绑定占位符提供一个值,这将具有与您编写
ORDER BY 'some literal'
相同的效果。

这根本没有真正对行进行任何排序。

(至少在我使用过的 DB2、Teradata、Oracle、SQL Server、MySQL 和 MariaDB(JDBC、Perl DBI、ODBC、Pro/C 等)的每个 SQL 客户端库中都是如此。)

(MyBatis 确实提供了一种方便的机制,可以在 SQL 文本中进行变量替换,在准备 SQL 文本之前动态更改 SQL 文本,但这些替换是在准备语句之前处理的,并且不会变成语句中的绑定占位符。)

通过 ORDER BY 子句中一些精心设计的表达式可以获得一些“动态”排序。例如,我们可以让静态 SQL 文本如下所示:

  ORDER BY CASE WHEN :sort_param = 'name ASC'  THEN activation_name END ASC
         , CASE WHEN :sort_param = 'name DESC' THEN activation_name END DESC

(这里的SQL文本不是动态的,它实际上是静态的,就像我们写的一样。

 ORDER BY expr1 ASC
        , expr1 DESC

“技巧”是 ORDER BY 子句中的表达式有条件地返回每行中某个列的值,或者返回一个文字(在上面的示例中,文字 NULL),具体取决于 a 的值绑定值,在执行时评估。

最终效果是我们可以“动态”获得以下任一效果:

 ORDER BY activation_name ASC, NULL DESC

 ORDER BY NULL ASC, activation_name DESC

 ORDER BY NULL ASC, NULL DESC

取决于我们为 :sort_param 占位符提供的值。


1
投票

您可以将 pageable 与 SpEL 语言一起使用。

Sort
中的
Pageable
对象将用于在请求末尾附加
" order by "
这里是一个例子。


1
投票

使用 createNativeQuery 并直接将按值排序作为字符串附加到查询中,而不是使用 setParameter()。对我来说效果很好。


1
投票

我在 Spring Boot 中使用本机查询也遇到了同样的问题,我发现的方法是:

1- 创建可分页:

Pageable pageable = PageRequest.of(numPage, sizePage, Sort.by(direction , nameField));

2- 在查询中添加“

ORDER BY true
”,例如:

@Query(value = " SELECT  * " +
            "FROM articulos a   " +
            "WHERE " +            
            "AND a.id = :id" +           
            "ORDER BY TRUE",
        countQuery = " SELECT  * " +
            "FROM articulos a   " +
            "WHERE " +            
            "AND a.id = :id" +           
            "ORDER BY TRUE"
        , nativeQuery = true)
    Page<PrecioArticuloVO> obtenerPreciosPorCategoriaProveedor(@Param("id")Long id,Pageable pagina);

0
投票

经过这么多次尝试,我尝试了下面的一个,它对我有用。

  1. 首先需要删除原生 Query = true,因为 JPQL 不允许在 jpa 查询中进行限制和偏移
  2. 接下来从查询本身中删除 order by :orderClause offset :offset limit :limit "
  3. 重新编写jpa repo方法如下 列表 findSirenAlarmTimeActivation(@Param("activationUUIDs") 列表激活UUID,可分页可分页)
  4. 调用上面的jpa方法,如下所示通过PageRequest.of(offset, pageSize, Sort.by(Sort.Order.asc(sortBy))))

@查询(“选择 a.name 作为activation_name, 分钟(transition_from_active_in_millis), 最大值(transition_from_active_in_millis), 来自 target_status_history t 的 avg(transition_from_active_in_millis),activation_scenario a 其中 t.activation_uuid=a.activation_scenario_id 和 t.transition_from_active_in_millis > 0 且 (:activationUUIDs) 中的 t.activation_uuid 按 a.name、t.activation_uuid 分组” ) 列表 findSirenAlarmTimeActivation(@Param("activationUUIDs") 列表激活UUID,可分页可分页)

findSirenAlarmTimeActivation(UUIDList, PageRequest.of(offset, pageSize, Sort.by(Sort.Order.asc(sortBy))));

就是这样,它对我有用,分页,排序

© www.soinside.com 2019 - 2024. All rights reserved.