Запрос JPA 2 возвращает неполные результаты

Следующий запрос соответствует только первому значению, найденному в подзапросе select, хотя есть совпадения для всех значений SELECT p FROM Profile p WHERE p.id IN (SELECT u.group FROM User u WHERE u.id = ?1)

Подзапрос возвращает список, разделенный запятыми, например: 1,2,3. Запрос должен возвращать совпадения для всех трех результатов выбора подзапроса. Кто-нибудь знает, что может быть не так? Спасибо.


person Mads610    schedule 21.10.2010    source источник
comment
Можете показать структуру таблицы? Похоже, что User.id должен быть вашим первичным ключом. Ваш подзапрос фильтрует это, поэтому, похоже, вы получите только один результат.   -  person MikeTheReader    schedule 21.10.2010
comment
Вы правы; есть (и должен быть) только один результат. Однако этот результат представляет собой строку, разделенную запятыми. Таким образом, подзапрос для u.group должен возвращать 1,2,3. Тогда запрос должен быть select p from Profile p where p.id in (1,2,3)... Который, в свою очередь, должен возвращать несколько результатов.   -  person Mads610    schedule 21.10.2010
comment
Итак, ваше значение u.group равно «1,2,3»? Никогда не рекомендуется использовать значения, разделенные запятыми, в поле базы данных. Это говорит о необходимости другой структуры в вашей базе данных.   -  person MikeTheReader    schedule 22.10.2010


Ответы (2)


Предложение IN не работает таким образом ни в JPQL, ни в SQL.

Значение внутри (..) не является «строкой, разделенной запятыми», это список значений. Этот список может быть указан буквально как строка, разделенная запятыми, или он может быть создан с помощью подзапроса, как в вашем случае. То есть условие в вашем запросе работает как p.id IN ("1,2,3") (а не p.id IN (1,2,3)), поэтому оно не дает желаемого результата.

Таким образом, вы не можете использовать мощь языков запросов (JPQL или SQL) для написания запросов к денормализованной схеме (ваш столбец содержит список значений, поэтому он нарушает 1NF). Если у вас есть отношение «многие ко многим» между Profiles и Users, выразите его как отношение «многие ко многим» с промежуточной таблицей соединений.

person axtavt    schedule 21.10.2010

Хотя оператор IN поддерживает сравнение с результатами подзапроса, то, что вы делаете, не может работать (и я удивлен, что вы получили хотя бы один результат). Прежде чем идти дальше, позвольте мне процитировать спецификацию JPA 2.0:

4.6.9 В выражениях

Синтаксис использования оператора сравнения [NOT] IN в условном выражении следующий:

 in_expression ::=
    {state_field_path_expression | type_discriminator} [NOT] IN
        { ( in_item {, in_item}* ) | (subquery) | collection_valued_input_parameter }
in_item ::= literal | single_valued_input_parameter 

state_field_path_expression должен иметь строковое, числовое значение, дату, время, временную метку или перечисляемое значение.

Значения литерала и/или входного параметра должны быть похожи на тот же тип абстрактной схемы, что и state_field_path_expression по типу. (См. Раздел 4.12).

Результаты подзапроса должны быть подобны тому же типу абстрактной схемы, что и state_field_path_expression по типу. Подзапросы обсуждаются в разделе 4.6.16.

Примеры:

o.country IN (’UK’, ’US’, ’France’) истинно для UK и ложно для Peru и эквивалентно выражению (o.country = ’UK’) OR (o.country = ’US’) OR (o.country = ’ France’).

o.country NOT IN (’UK’, ’US’, ’France’) является ложным для UK и истинным для Peru и эквивалентно выражению NOT ((o.country = ’UK’) OR (o.country = ’US’) OR (o.country = ’France’)).

В списке, разделенном запятыми, должен быть хотя бы один элемент, определяющий набор значений для выражения IN.

Если значение state_field_path_expression или in_item в выражении IN или NOT IN равно NULL или неизвестно, значение выражения неизвестно.

Обратите внимание, что использование входного параметра со значением коллекции будет означать, что статический запрос не может быть предварительно скомпилирован.

Итак, во-первых, p.id не соответствует возвращаемому типу подвыборки (что на самом деле является «незначительной» проблемой).

Во-вторых, и это серьезная проблема и недоразумение, ваш запрос не приведет к чему-то подобному (с использованием «псевдокода»):

p.id IN (1, 2, 3) 

это то, что вы хотели бы, но в

p.id IN (’1,2,3’) 

что, очевидно, не то, что вы хотите, и не будет работать.

Мой единственный совет: нормализуйте свою базу данных.

person Pascal Thivent    schedule 21.10.2010