HQL Где IN для пустого списка вылетает

У меня есть такой оператор HQL:

Select cast(ed.employee.employeeID as int) AS emp_id FROM Education AS ed WHERE ed.type.name IN (:typeNames)

Однако иногда typeNames пуст. Это вызывает следующее:

org.hibernate.hql.ast.QuerySyntaxException: unexpected end of subtree [Select cast(ed.employee.employeeID as int) AS emp_id FROM Education AS ed WHERE ed.type.name IN ()]

Каково решение, чтобы принять пустой список?


person Derek    schedule 09.12.2011    source источник
comment
каким должно быть поведение, если список пуст - получить все или ничего?   -  person aishwarya    schedule 09.12.2011
comment
Он не должен возвращать никаких результатов, если есть пустой список   -  person Derek    schedule 09.12.2011
comment
Разве вы не можете просто проверить список, прежде чем передавать его в качестве аргумента в запрос HQL? Я считаю, что HQL просто отражает поведение SQL, который также выдаст ошибку, если вы попытаетесь выполнить запрос IN ()?   -  person sbrattla    schedule 10.12.2011
comment
@ Дерек, я согласен с Тедом. если вы ищете пустой список в этом условии, зачем вообще выполнять запрос :-)   -  person aishwarya    schedule 10.12.2011
comment
В Hibernate jira есть (в настоящее время) открытая ошибка, связанная с пустой проблемой IN(): hibernate.atlassian. сеть/обзор/HHH-8091   -  person omnomnom    schedule 29.03.2013


Ответы (4)


Одним из решений, которое я использовал, было бы размещение некоторого фиктивного значения в списке вместе с вашим вводом, чтобы гарантировать, что он никогда не будет пустым. Конечно, вы можете сделать это, только если можно выбрать фиктивное значение.

Если ваш список ввода typeNamesOrig:

List<String> typeNames = new ArrayList<String>(typeNamesOrig);
typeNames.add("valueThatDoesNotExistForSure");
query.setParameterList("typeNames",typeNames);
person Alex Gitelman    schedule 09.12.2011
comment
Это не будет работать, если вы используете коллекцию перечислений. Поскольку вы можете использовать только значения перечисления, а не какую-то несуществующую строку, вероятность того, что каждое значение перечисления вернет один или несколько результатов, довольно высока. И создание дополнительного значения перечисления EMPTY только для этой цели было бы излишним и очень уродливым. - person lugte098; 03.07.2014
comment
Этот обходной путь решает проблему и в то же время вводит новую, я настоятельно рекомендую рассмотреть другие ответы. - person Pavel; 23.03.2017
comment
@Pavel Здесь нет других законных ответов ... :( - person Josh M.; 30.01.2019

Если typeNames пуст/нуль, я, вероятно, не буду выполнять запрос:

if (typeNames) result = Foo.executeQuery("select ... where e.type.name in :typeNames", [typeNames: typeNames)
person Ted Naleid    schedule 10.12.2011
comment
Можете ли вы объяснить, почему нет? Поскольку любое имя типа никогда не будет включено в пустой список, я ожидаю, что ничего нельзя будет выбрать. Таким образом, результирующий набор пуст. - person Lars Blumberg; 10.07.2013
comment
В основном потому, что он экономит время на обращение к базе данных, чтобы определить что-то, что мы можем знать в коде, а также потому, что он решает проблему в спящем режиме, которая заставляет такие вещи, как принятый ответ, помещать фиктивное значение в список. - person Ted Naleid; 10.07.2013
comment
@Ted Иногда казни не избежать. Я сталкиваюсь с той же проблемой, и в запросе есть предложение OR в предложении WHERE. Все остальные параметры привязки имеют допустимые значения, и запрос возвращает результаты, даже если список пуст. В моем сценарии опасно использовать фиктивные значения, так что это тупик. Есть ли другое решение? - person Ilias Stavrakis; 14.01.2016
comment
Есть запросы, которые вы все равно хотите выполнить, даже если коллекция пуста. Действительные заботы — это то, где вы используете необязательную коллекцию excludeIds, чтобы исключить определенные строки из обновления. - person djmj; 22.03.2020

Вы можете установить список :typeNames как null, если массив пуст.

if(typeNames.isEmpty()) typeNames = null

// Call Query

person Dayoung    schedule 14.05.2019

Фиктивное значение, безусловно, является самым простым решением, за исключением того, что вы никогда не знаете наверняка, что значение не существует. Лучшее, что вы можете сделать, это добавить еще одну переменную, чтобы указать, что список пуст.

select *
from books
where id in (:ids) and :listHasItems = 1

если в вашем списке нет элементов, просто добавьте к нему случайный идентификатор и установите для listHasItems значение 0.

person Nactive    schedule 06.04.2015
comment
Я думаю, что это все равно приведет к недопустимому SQL - person Christoph Baudson; 21.10.2016