This is the answer I get when I tries to do like you it is working with some modification.
In my case I had the problem that my optional parameter was a List<String>
and the solution was the following:
@Query(value = "SELECT *
FROM ...
WHERE (COLUMN_X IN :categories OR COALESCE(:categories, null) IS NULL)"
, nativeQuery = true)
List<Archive> findByCustomCriteria1(@Param("categories") List<String> categories);
This way:
- If the parameter has one or more values it is selected by the left side of the OR operator
- If the parameter categories is null, meaning that i have to select all values for COLUMN_X, will always return TRUE by the right side of the OR operator
Why COALESCE
and why a null value inside of it?
Let's explore the WHERE
clause in all conditions:
Case 1: categories = null
(COLUMN_X IN null OR COALESCE(null, null) IS NULL)
The left part of the OR will return false, while the right part of the OR will always return true, in fact COALESCE
will return the first non-null value if present and returns null if all arguments are null.
Case 2: categories = ()
(COLUMN_X IN null OR COALESCE(null, null) IS NULL)
JPA will automatically identify an empty list as a null value, hence same result of Case 1.
Case 3: categories = ('ONE_VALUE')
(COLUMN_X IN ('ONE_VALUE') OR COALESCE('ONE_VALUE', null) IS NULL)
The left part of the OR will return true only for those values for which COLUMN_X = 'ONE_VALUE'
while the right part of the OR will never return true, because it is equals to 'ONE_VALUE' IS NULL
(that is false).
Why the null as second parameter? Well, that's because COALESCE
needs at least two parameters.
Case 4: categories = ('ONE_VALUE', 'TWO_VALUE')
(COLUMN_X IN ('ONE_VALUE', 'TWO_VALUE') OR COALESCE('ONE_VALUE', 'TWO_VALUE', null) IS NULL)
As in Case 3, the left part of the OR operator will select only the rows for which COLUMN_X
is equale to 'ONE_VALUE'
or 'TWO_VALUE'
.