Использование CTE может быть самым простым решением.
Вы можете передать список дат в качестве параметра.
Map<Date, List<Product>> map = new HashMap<>();
Map<String, Object> param = new HashMap<>();
param.put("dates", list_date);
List<Map<String, ?>> result = this.queryForList("getProductForDate", param);
Оператор и карта результатов могут выглядеть следующим образом:
<select id="getValidProductsInternal" resultMap="productsPerDate">
with dates(d) as (
<foreach item="date" collection="dates" separator="union all">
select #{date,jdbcType=DATE} as d from dual
</foreach>
)
select dates.d date_in_question, t.product_id
from dates
left join my_table t on
dates.d >= t.valid_from and t.valid_till > dates.d
</select>
<resultMap type="map" id="productsPerDate">
<id column="date_in_question" property="date" />
<collection property="products" javaType="list"
ofType="test.Product">
<id column="product_id" property="id" />
</collection>
</resultMap>
Объяснение CTE может быть не по теме, а проще говоря, предложение with
создает виртуальную таблицу (своего рода) dates
с одним столбцом d
типа DATE
.
Создается строка для каждого Date
в параметре dates
, поэтому, если вы передадите три Date
s в качестве параметра, в таблице dates
будет три строки.
select ... left join
часть может быть простой.
Теперь результат может содержать каждую дату в списке, даже если на эту дату нет действительного продукта.
Например ...
[
{
date : 2019-01-01,
products : [
{id: 2, ...}
]
},
{
date : 2019-01-03,
products : [
{id: 1, ...},
{id: 2, ...}
]
},
{
date : 2019-01-05,
products : []
},
...
]
Хотя этот результат не совсем то, что вы хотите, его легко конвертировать.
Map<Date, List<Product>> validProductsPerDate = result.stream()
.collect(Collectors.toMap(
e -> (Date) e.get("date"),
e -> (List<Product>) e.get("products")));
Вот исполняемый файл demo .
Демонстрация использует интерфейс mapper и включает в себя как примеры случайных, так и последовательных дат.