Динамический запрос SQL с учетом фильтров

Рейтинг: 0Ответов: 2Опубликовано: 01.02.2023

подскажите можно ли как то создать динамический SQL запрос, что я имею ввиду? Вот у меня в клиенте есть условных 6 фильтров, которые пользователь может выбирать, а может и не выбирать, если ли способ фильтровать выводимые пользователю данные только с учетом выбранных им фильтров, при этом, не создавать кучу условий в программном коде, учитывая каждый возможный случай.

Привожу пример, если было бы два фильтра user_type и document_type. Тогда в коде я бы написал 4 условия.

  1. Если не выбран ни один из фильтров, то есть вывожу все данные из таблицы.
  2. Если выбран только определенный user_type
  3. Если выбран только определенный document_type
  4. Если выбраны оба фильтра

Ответы

▲ 2

Можно использовать mybatis.

Он позволяет создавать динамические SQL запросы и мапить результат в объекты (это не полноценный ORM, а продвинутый маппер). Также он поддерживает скриптовые движки шаблонов, в частности velocity.

Если использовать mybatis вместе со стандартным плагином к velocity, то запрос будет выглядеть приблизительно так:

SELECT *
FROM MyEntity
#where()
  #if($_parameter.user_type)
    @{user_type} = user_type
  #end
  #if($_parameter.document_type)
    AND @{document_type} = document_type
  #end
#end

При вызове метода мапера mybatis сгенерирует запрос включая части условия в зависимости от того, какие параметры заданы. Если ничего не задано, то никакого WHERE вообще не будет и вернутся все данные.

▲ 1

Если у вас используется Spring Data, то можно использовать JpaSpecificationExecutor и написать свою типизированную спецификацию для поиска, или QueryDslPredicateExecutor с QueryDSL, чтобы написать предикат. См. Filtering database rows with spring-data-jpa and spring-mvc

Также можно написать SQL-запрос, в котором параметры могут пропускаться путем сравнения с null:

@Query("""
       select ye from YourEntity ye where
       (?1 is null or ye.user_type = ?1)
       and (?2 is null or ye.document_type = ?2)
       """)
List<YourEntity> findFiltered(String userType, String documentType);