Я использую EclipseLink 2.6.4
, Java 8
и DB2
для базы данных. Мне нужно написать запрос для чтения данных с оператором NOT IN
, обеспечивающим большой набор значений для оператора NOT IN
.
В основном у меня есть набор внешних идентификаторов с более чем 10000 значениями:
Set<Integer> externalIDs = new HashSet<>(Arrays.asList("ExternalID1", "ExternalID2", "ExternalID3",....)); //externalIDs.size() == 10k+
Примечание: я знаю, что предел для оператора NOT IN
с DB2 составляет 1000 значений, поэтому я создаю в запросе разделенные операторы NOT IN
, и он выглядит следующим образом:
public List<UserEntity> findNotReferencedToRemove2(Set<String> externalIds) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<UserEntity> cq = cb.createQuery(UserEntity.class);
Root<UserEntity> root = cq.from(UserEntity.class);
Path<String> externalId1 = root.get(UserEntity_.relation1).get(RelationEntity1_.externalId);
Path<String> externalId2 = root.get(UserEntity_.relation2).get(RelationEntity2_.externalId);
Path<String> externalId3 = root.get(UserEntity_.relation3).get(RelationEntity3_.externalId);
Path<String> externalId4 = root.get(UserEntity_.relation4).get(RelationEntity4_.externalId);
Path<String> externalId5 = root.get(UserEntity_.relation5).get(RelationEntity5_.externalId);
Predicate predicate = cb.and(
partitionedNotIn(cb, externalId1, externalIds),
partitionedNotIn(cb, externalId2, externalIds),
partitionedNotIn(cb, externalId3, externalIds),
partitionedNotIn(cb, externalId4, externalIds),
partitionedNotIn(cb, externalId5, externalIds)
);
return entityManager.createQuery(cq.where(predicate)).getResultList();
}
//creates NOT IN statement splited in chunks of 999 values connected with AND
private<C> Predicate partitionedNotIn(CriteriaBuilder cb, Path<C> path, Collection<C> ids) {
if (ids.isEmpty()) {
return cb.and();
}
return cb.and(partition(ids).stream().map(path::in).map(cb::not).toArray(Predicate[]::new));
}
private <C> Collection<List<C>> partition(Collection<C> list) {
final AtomicInteger counter = new AtomicInteger(0);
return list.stream()
.collect(Collectors.groupingBy(it -> counter.getAndIncrement() / 999))
.values();
}
Закрытый методpartionedNotIn()
просто разбивает операторы NOT IN
на куски из 999 значений, чтобы не достигнуть максимума 1000 значений.
Но, как вы можете видеть, у меня есть 5 NOT IN
операторов и для каждых 10000 предоставленных значений, и всего50000, и я достигаю предела в БД длины размещаемой переменной.
В любом случае, цель состоит в том, чтобы разбить это на куски, чтобы у меня не было 50k + значений для операторов NOT IN
и в настоящее время нетесть идеи как этого добиться. С помощью IN
заявления это будет легко.
Любое предложение будет полезным. Спасибо.