Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Полный синтаксис языка запросов

В этом разделе обсуждается синтаксис языка запросов, определённый в спецификации Java Persistence API 2.0, доступной по ссылке http://jcp.org/en/jsr/detail?id=317. Многое из следующего материала перефразирует или прямо цитирует спецификацию.

Здесь рассматриваются следующие темы:

Символы BNF

Таблица 42-1 описывает символы BNF, используемые в этой главе.

Таблица 42-1 Обзор символов BNF

Символ

Описание

::=

Элемент слева от символа определяется конструкциями справа.

*

Предыдущая конструкция может встречаться ноль или более раз.

{…​}

Конструкции в фигурных скобках сгруппированы вместе.

[…​]

Конструкции в квадратных скобках не являются обязательными.

|

Исключающее OR.

жирный шрифт

Ключевое слово. Хотя в диаграмме BNF они указаны прописными, ключевые слова не чувствительны к регистру.

Символ пробела

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

Грамматика BNF языка запросов персистентности Java

Вот полная диаграмма BNF для языка запросов:

QL_statement ::= select_statement | update_statement | delete_statement
select_statement ::= select_clause from_clause [where_clause] [groupby_clause]
    [having_clause] [orderby_clause]
update_statement ::= update_clause [where_clause]
delete_statement ::= delete_clause [where_clause]
from_clause ::=
    FROM identification_variable_declaration
        {, {identification_variable_declaration |
            collection_member_declaration}}*
identification_variable_declaration ::=
        range_variable_declaration { join | fetch_join }*
range_variable_declaration ::= abstract_schema_name [AS]
        identification_variable
join ::= join_spec join_association_path_expression [AS]
        identification_variable
fetch_join ::= join_specFETCH join_association_path_expression
association_path_expression ::=
        collection_valued_path_expression |
        single_valued_association_path_expression
join_spec::= [LEFT [OUTER] |INNER] JOIN
join_association_path_expression ::=
        join_collection_valued_path_expression |
        join_single_valued_association_path_expression
join_collection_valued_path_expression::=
    identification_variable.collection_valued_association_field
join_single_valued_association_path_expression::=
        identification_variable.single_valued_association_field
collection_member_declaration ::=
        IN (collection_valued_path_expression) [AS]
        identification_variable
single_valued_path_expression ::=
        state_field_path_expression |
        single_valued_association_path_expression
state_field_path_expression ::=
    {identification_variable |
    single_valued_association_path_expression}.state_field
single_valued_association_path_expression ::=
    identification_variable.{single_valued_association_field.}*
    single_valued_association_field
collection_valued_path_expression ::=
    identification_variable.{single_valued_association_field.}*
    collection_valued_association_field
state_field ::=
    {embedded_class_state_field.}*simple_state_field
update_clause ::=UPDATE abstract_schema_name [[AS]
    identification_variable] SET update_item {, update_item}*
update_item ::= [identification_variable.]{state_field |
    single_valued_association_field} = new_value
new_value ::=
     simple_arithmetic_expression |
    string_primary |
    datetime_primary |
    boolean_primary |
    enum_primary simple_entity_expression |
    NULL
delete_clause ::= DELETE FROM abstract_schema_name [[AS]
    identification_variable]
select_clause ::= SELECT [DISTINCT] select_expression {,
    select_expression}*
select_expression ::=
    single_valued_path_expression |
    aggregate_expression |
    identification_variable |
    OBJECT(identification_variable) |
    constructor_expression
constructor_expression ::=
    NEW constructor_name(constructor_item {,
    constructor_item}*)
constructor_item ::= single_valued_path_expression |
    aggregate_expression
aggregate_expression ::=
    {AVG |MAX |MIN |SUM} ([DISTINCT]
        state_field_path_expression) |
    COUNT ([DISTINCT] identification_variable |
        state_field_path_expression |
        single_valued_association_path_expression)
where_clause ::= WHERE conditional_expression
groupby_clause ::= GROUP BY groupby_item {, groupby_item}*
groupby_item ::= single_valued_path_expression
having_clause ::= HAVING conditional_expression
orderby_clause ::= ORDER BY orderby_item {, orderby_item}*
orderby_item ::= state_field_path_expression [ASC |DESC]
subquery ::= simple_select_clause subquery_from_clause
    [where_clause] [groupby_clause] [having_clause]
subquery_from_clause ::=
    FROM subselect_identification_variable_declaration
        {, subselect_identification_variable_declaration}*
subselect_identification_variable_declaration ::=
    identification_variable_declaration |
    association_path_expression [AS] identification_variable |
    collection_member_declaration
simple_select_clause ::= SELECT [DISTINCT]
    simple_select_expression
simple_select_expression::=
    single_valued_path_expression |
    aggregate_expression |
    identification_variable
conditional_expression ::= conditional_term |
    conditional_expression OR conditional_term
conditional_term ::= conditional_factor | conditional_term AND
    conditional_factor
conditional_factor ::= [NOT] conditional_primary
conditional_primary ::= simple_cond_expression |(
    conditional_expression)
simple_cond_expression ::=
    comparison_expression |
    between_expression |
    like_expression |
    in_expression |
    null_comparison_expression |
    empty_collection_comparison_expression |
    collection_member_expression |
    exists_expression
between_expression ::=
    arithmetic_expression [NOT] BETWEEN
        arithmetic_expressionAND arithmetic_expression |
    string_expression [NOT] BETWEEN string_expression AND
        string_expression |
    datetime_expression [NOT] BETWEEN
        datetime_expression AND datetime_expression
in_expression ::=
    state_field_path_expression [NOT] IN (in_item {, in_item}*
    | subquery)
in_item ::= literal | input_parameter
like_expression ::=
    string_expression [NOT] LIKE pattern_value [ESCAPE
        escape_character]
null_comparison_expression ::=
    {single_valued_path_expression | input_parameter} IS [NOT]
        NULL
empty_collection_comparison_expression ::=
    collection_valued_path_expression IS [NOT] EMPTY
collection_member_expression ::= entity_expression
    [NOT] MEMBER [OF] collection_valued_path_expression
exists_expression::= [NOT] EXISTS (subquery)
all_or_any_expression ::= {ALL |ANY |SOME} (subquery)
comparison_expression ::=
    string_expression comparison_operator {string_expression |
    all_or_any_expression} |
    boolean_expression {= |<> } {boolean_expression |
    all_or_any_expression} |
    enum_expression {= |<> } {enum_expression |
    all_or_any_expression} |
    datetime_expression comparison_operator
        {datetime_expression | all_or_any_expression} |
    entity_expression {= |<> } {entity_expression |
    all_or_any_expression} |
    arithmetic_expression comparison_operator
        {arithmetic_expression | all_or_any_expression}
comparison_operator ::= = |> |>= |< |<= |<>
arithmetic_expression ::= simple_arithmetic_expression |
    (subquery)
simple_arithmetic_expression ::=
    arithmetic_term | simple_arithmetic_expression {+ |- }
        arithmetic_term
arithmetic_term ::= arithmetic_factor | arithmetic_term {* |/ }
    arithmetic_factor
arithmetic_factor ::= [{+ |- }] arithmetic_primary
arithmetic_primary ::=
    state_field_path_expression |
    numeric_literal |
    (simple_arithmetic_expression) |
    input_parameter |
    functions_returning_numerics |
    aggregate_expression
string_expression ::= string_primary | (subquery)
string_primary ::=
    state_field_path_expression |
    string_literal |
    input_parameter |
    functions_returning_strings |
    aggregate_expression
datetime_expression ::= datetime_primary | (subquery)
datetime_primary ::=
    state_field_path_expression |
    input_parameter |
    functions_returning_datetime |
    aggregate_expression
boolean_expression ::= boolean_primary | (subquery)
boolean_primary ::=
    state_field_path_expression |
    boolean_literal |
    input_parameter
 enum_expression ::= enum_primary | (subquery)
enum_primary ::=
    state_field_path_expression |
    enum_literal |
    input_parameter
entity_expression ::=
    single_valued_association_path_expression |
        simple_entity_expression
simple_entity_expression ::=
    identification_variable |
    input_parameter
functions_returning_numerics::=
    LENGTH(string_primary) |
    LOCATE(string_primary, string_primary[,
        simple_arithmetic_expression]) |
    ABS(simple_arithmetic_expression) |
    SQRT(simple_arithmetic_expression) |
    MOD(simple_arithmetic_expression,
        simple_arithmetic_expression) |
    SIZE(collection_valued_path_expression)
functions_returning_datetime ::=
    CURRENT_DATE |
    CURRENT_TIME |
    CURRENT_TIMESTAMP
functions_returning_strings ::=
    CONCAT(string_primary, string_primary) |
    SUBSTRING(string_primary,
        simple_arithmetic_expression,
        simple_arithmetic_expression)|
    TRIM([[trim_specification] [trim_character] FROM]
        string_primary) |
    LOWER(string_primary) |
    UPPER(string_primary)
trim_specification ::= LEADING | TRAILING | BOTH

Выражение FROM

Предложение FROM определяет область запроса путём объявления идентификационных переменных.

Здесь рассматриваются следующие темы:

Идентификаторы

Идентификатор — это последовательность из одного или нескольких символов. Правила к именам идентификаторов такие же, как и к идентификаторам в Java. (Подробнее см. документацию по API Java SE для методов isJavaIdentifierStart и isJavaIdentifierPart класса Character.) Знак вопроса (?) является зарезервированным символом в языке запросов и не может использоваться в идентификаторе.

Идентификатор языка запросов чувствителен к регистру, с двумя исключениями:

  • Ключевые слова

  • Идентификационные переменные

Идентификатор не может совпадать с ключевым словом языка запросов. Вот список ключевых слов языка запросов:

ABS
ALL
AND
ANY
AS
ASC
AVG
BETWEEN
BIT_LENGTH
BOTH
BY
CASE
CHAR_LENGTH
CHARACTER_LENGTH
CLASS
COALESCE
CONCAT
COUNT
CURRENT_DATE
CURRENT_TIMESTAMP
DELETE
DESC
DISTINCT
ELSE
EMPTY
END
ENTRY
ESCAPE
EXISTS
FALSE
FETCH
FROM
GROUP
HAVING
IN
INDEX
INNER
IS
JOIN
KEY
LEADING
LEFT
LENGTH
LIKE
LOCATE
LOWER
MAX
MEMBER
MIN
MOD
NEW
NOT
NULL
NULLIF
OBJECT
OF
OR
ORDER
OUTER
POSITION
SELECT
SET
SIZE
SOME
SQRT
SUBSTRING
SUM
THEN
TRAILING
TRIM
TRUE
TYPE
UNKNOWN
UPDATE
UPPER
VALUE
WHEN
WHERE

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

Идентификационные переменные

Идентификационная переменная — это идентификатор, объявленный в предложении FROM. Хотя они могут ссылаться на идентификационные переменные, предложения SELECT и WHERE не могут их объявить. Все идентификационные переменные должны быть объявлены в предложении FROM.

Поскольку это идентификатор, идентификационная переменная подчиняется тем же соглашениям и ограничениям именования, что и идентификатор, за исключением того, что идентификационная переменная не зависит от регистра. Например, переменная идентификации не может совпадать с ключевым словом языка запросов. (Дополнительные правила именования см. в Идентификаторах.) Кроме того, в пределах данного юнита персистентности имя идентификационной переменной не должно совпадать с именем сущности или типом схемы абстракций.

Предложение FROM может содержать несколько объявлений, разделённых запятыми. Объявление может ссылаться на другую идентификационную переменную, объявленную ранее (слева). В следующем предложении FROM переменная t ссылается на ранее объявленную переменную p:

FROM Player p, IN (p.teams) AS t

Даже если она не используется в предложении WHERE, объявление идентификационной переменной может повлиять на результаты запроса. Например, сравните следующие два запроса. Этот запрос возвращает всех игроков, независимо от их принадлежности к какой-либо команде:

SELECT p
FROM Player p

Следующий запрос напротив, выбирает только игроков, принадлежащих к какой-либо команде, поскольку он объявляет идентификационную переменную t:

SELECT p
FROM Player p, IN (p.teams) AS t

Следующий запрос возвращает те же результаты, что и предыдущий запрос, но предложение WHERE облегчает чтение:

SELECT p
FROM Player p
WHERE p.teams IS NOT EMPTY

Идентификационная переменная всегда обозначает ссылку на одно значение, тип которого является типом выражения, используемого в объявлении. Существует два вида объявлений: переменная диапазона и член коллекции.

Объявления переменных диапазона

Чтобы объявить идентификационную переменную как тип схемы абстракций, укажите переменную диапазона. Другими словами, переменная идентификации может варьироваться по типу схемы абстракций. В следующем примере идентификационная переменная с именем p представляет тип Player схемы абстракций:

FROM Player p

Объявление переменной диапазона может включать в себя необязательный оператор $:

FROM Player AS p

Чтобы получить объекты, запрос обычно использует выражения пути для навигации по отношениям. Но для тех объектов, которые не могут быть получены с помощью навигации, вы можете использовать объявление переменной диапазона для обозначения начальной точки или корня запроса.

Если запрос сравнивает несколько значений одного и того же типа схемы абстракций, предложение FROM должно объявить несколько идентификационных переменных для схемы абстракций:

FROM Player p1, Player p2

Пример такого запроса см. в разделе Операторы сравнения.

Объявления членов коллекции

В отношении «один ко многим» множественная сторона состоит из набора сущностей. Идентификационная переменная может представлять член этой коллекции. Чтобы получить доступ к элементу коллекции, выражение пути в объявлении переменной перемещается по отношениям в схеме абстракций. (Для получения дополнительной информации о выражениях пути см. Выражения пути.) Поскольку выражение пути может быть основано на другом выражении пути, навигация может проходить через несколько отношений. Смотрите Обход множественных отношений.

Объявление члена коллекции должно включать оператор IN, но может опускать необязательный оператор $.

В следующем примере сущность, представленная типом Player схемы абстракций, имеет поле отношения teams. Идентификационная переменная t представляет одного члена коллекции teams:

FROM Player p, IN (p.teams) t

Объединения

Оператор JOIN используется для обхода отношений между сущностями и функционально аналогичен оператору IN.

В следующем примере запрос объединяет клиентов и заказы по отношению между ними:

SELECT c
FROM Customer c JOIN c.orders o
WHERE c.status = 1 AND o.totalPrice > 10000

Ключевое слово INNER необязательно:

SELECT c
FROM Customer c INNER JOIN c.orders o
WHERE c.status = 1 AND o.totalPrice > 10000

Эти примеры эквивалентны следующему запросу, в котором используется оператор IN:

SELECT c
FROM Customer c, IN (c.orders) o
WHERE c.status = 1 AND o.totalPrice > 10000

Вы также можете присоединиться к однозначным отношениям:

SELECT t
FROM Team t JOIN t.league l
WHERE l.sport = :sport

LEFT JOIN или LEFT OUTER JOIN извлекает набор объектов, в которых совпадающие значения в условии соединения могут отсутствовать. Ключевое слово OUTER необязательно:

SELECT c.name, o.totalPrice
FROM CustomerOrder o LEFT JOIN o.customer c

FETCH JOIN — это операция объединения, которая возвращает связанные сущности в качестве побочного эффекта выполнения запроса. В следующем примере запрос возвращает набор отделов и, как побочный эффект, связанных сотрудников отделов, даже если сотрудники не были явно запрошены предложением SELECT:

SELECT d
FROM Department d LEFT JOIN FETCH d.employees
WHERE d.deptno = 1

Выражения пути

Выражения пути являются важными конструкциями в синтаксисе языка запросов по нескольким причинам. Во-первых, выражения пути определяют пути навигации по отношениям в схеме абстракций. Эти определения пути влияют как на объём, так и на результаты запроса. Во-вторых, выражения пути могут появляться в любом из основных предложений запроса (SELECT, DELETE, HAVING, UPDATE, WHERE, FROM, GROUP BY, ORDER BY). Наконец, хотя большая часть языка запросов является подмножеством SQL, выражения пути являются расширениями, которых нет в SQL.

Здесь рассматриваются следующие темы:

Примеры выражений пути

Здесь предложение WHERE содержит single_valued_path_expression. p является идентификационной переменной, а salary персистентным полем Player:

SELECT DISTINCT p
FROM Player p
WHERE p.salary BETWEEN :lowerSalary AND :higherSalary

Здесь, предложение WHERE также содержит single_valued_path_expression. t является идентификационной переменной, league однозначным полем отношений, а sport персистентным полем league:

SELECT DISTINCT p
FROM Player p, IN (p.teams) t
WHERE t.league.sport = :sport

Здесь предложение WHERE содержит collection_valued_path_expression. p является идентификационной переменной, а teams обозначает поле отношения со значением коллекции:

SELECT DISTINCT p
FROM Player p
WHERE p.teams IS EMPTY

Типы выражений

Тип выражения пути — это тип объекта, представленного конечным элементом, который может быть одним из следующих:

  • Персистентное поле

  • Однозначное поле отношения

  • Поле отношения с коллекцией

Например, выражения p.salary имеет тип double, потому что завершающее персистентное поле (salary) имеет тип double.

В выражении p.teams завершающий элемент является полем отношений (teams). Тип этого выражения является коллекцией объектов типа Team схемы абстракций. Team является типом схемы абстракций для сущности Team и отображается на эту сущность. Для получения дополнительной информации о сопоставлении типов абстрактных схем см. Возвращаемые типы.

Навигация

Выражение пути позволяет запросу перемещаться к связанным объектам. Завершающие элементы выражения определяют, разрешена ли навигация. Если выражение содержит однозначное поле отношения, навигация может продолжаться к объекту, связанному с полем. Однако выражение не может выходить за пределы персистентного поля или поля отношения со значением коллекции. Например, выражение p.teams.league.sport недопустимо, потому что teams является полем отношений со значением коллекции. Чтобы достичь поля sport, предложение FROM может определить идентификационную переменную t для поля teams:

FROM Player AS p, IN (p.teams) t
WHERE t.league.sport = 'football'

Выражение WHERE

Предложение WHERE определяет условное выражение, которое фильтрует значения, возвращаемые запросом. Запрос возвращает все соответствующие значения из хранилища данных, для которого значение условного выражения TRUE. Предложение WHERE является необязательным, хотя обычно оно указывается. Если предложение WHERE опущено, запрос возвращает все значения. Синтаксис высокого уровня для предложения WHERE выглядит следующим образом:

where_clause ::= WHERE conditional_expression

Здесь рассматриваются следующие темы:

Литералы

Существует четыре вида литералов: строковые, числовые, логические и перечисления.

  • Строковые литералы: строковый литерал заключён в одинарные кавычки:

    'Duke'

    Если строковый литерал содержит одну кавычку, вы указываете кавычку с помощью двух одинарных кавычек:

    'Duke''s'

    Подобно String в Java, строковый литерал в языке запросов использует кодировку символов Unicode.

  • Числовые литералы. Существует два типа числовых литералов: точные и приблизительные.

    • Точный числовой литерал — это числовое значение без десятичной точки, например 65, –233 и +12. Используя целочисленный синтаксис Java, точные числовые литералы поддерживают числа в диапазоне long Java.

    • Приблизительный числовой литерал — это числовое значение в научной нотации, например 57., –85.7 и +2.1. Используя синтаксис литерала Java с плавающей точкой, приближенные числовые литералы поддерживают числа в диапазоне double Java.

  • Логические литералы: логический литерал имеет значение TRUE или FALSE. Эти ключевые слова не чувствительны к регистру.

  • Перечислимые литералы Enum. Язык запросов персистентности Java поддерживает использование литералов enum с использованием синтаксиса литералов enum Java. Имя класса enum должно быть указано как полное имя класса:

    SELECT e
    FROM Employee e
    WHERE e.status = com.example.EmployeeStatus.FULL_TIME

Входные параметры

Входные параметры могут быть именованными или позиционными.

  • Именованный входной параметр обозначается двоеточием (:), за которым следует строка. Например, :name.

  • Позиционный входной параметр обозначается знаком вопроса (?), за которым следует целое число. Например, первый входной параметр — это ?1, второй — ?2 и так далее.

Следующие правила применяются к входным параметрам.

  • Они могут использоваться только в предложении WHERE или HAVING.

  • Позиционные параметры должны быть пронумерованы, начиная с 1.

  • Именованные параметры и позиционные параметры не могут быть смешаны в одном запросе.

  • Именованные параметры чувствительны к регистру.

Условные выражения

Предложение WHERE состоит из условного выражения, которое вычисляется слева направо в пределах уровня приоритета. Вы можете изменить порядок выполнения, используя скобки.

Операторы и их приоритет

Таблица 42-2 перечисляет операторы языка запросов в порядке убывания приоритета.

Таблица 42-2. Порядок приоритетов языка запросов

Тип

Порядок приоритета

Навигация

. (точка)

Арифметические

+ - (одинарный)

*/ (умножение и деление)

+ - (сложение и вычитание)

Сравнения

=

>

>=

<

<> (не равно)

[NOT] BETWEEN

[NOT] LIKE

[NOT] IN

IS [NOT] NULL

IS [NOT] EMPTY

[NOT] MEMBER OF

Логические

NOT

AND

OR

Выражения BETWEEN

Выражение BETWEEN определяет, попадает ли арифметическое выражение в диапазон значений.

Эти два выражения эквивалентны:

p.age BETWEEN 15 AND 19
p.age >= 15 AND p.age <= 19

Следующие два выражения также эквивалентны:

p.age NOT BETWEEN 15 AND 19
p.age < 15 OR p.age > 19

Если арифметическое выражение имеет значение NULL, значение выражения BETWEEN неизвестно.

Выражения IN

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

Выражение пути должно иметь строковое или числовое значение. Если выражение пути имеет значение NULL, значение выражения IN неизвестно.

В следующем примере выражение равно TRUE, если страна UK, но FALSE, если страна Peru :

o.country IN ('UK', 'US', 'France')

Также могут использоваться входные параметры:

o.country IN ('UK', 'US', 'France', :country)

Выражения LIKE

Выражение LIKE определяет, соответствует ли шаблон подстановки строке.

Выражение пути должно иметь строковое или числовое значение. Если это значение равно NULL, значение выражения LIKE неизвестно. Значением шаблона является строковый литерал, который может содержать символы подстановки. Подстановочный знак (_) обозначает любой отдельный символ. Подстановочный знак процента (%) представляет собой ноль или более символов. Предложение ESCAPE определяет escape-символ для символов подстановки в значении шаблона. Таблица 42-3 показывает некоторые примеры выражений LIKE.

Таблица 42-3 Примеры выражения LIKE

Выражение

TRUE

FALSE

address.phone LIKE '12%3'

'123'

'12993'

'1234'

asentence.word LIKE 'l_se'

'lose'

'loose'

aword.underscored LIKE '\_%' ESCAPE '\'

'_foo'

'bar'

address.phone NOT LIKE '12%3'

'1234'

'123'

'12993'

Выражения сравнения с NULL

Выражение сравнения с NULL проверяет, имеет ли однозначное выражение пути или входной параметр значение NULL. Обычно выражение сравнения с NULL используется для проверки, установлено ли однозначное отношение:

SELECT t
FROM Team t
WHERE t.league IS NULL

Этот запрос выбирает все команды без установленной лиги. Обратите внимание, что следующий запрос не эквивалентен предыдущему:

SELECT t
FROM Team t
WHERE t.league = NULL

Сравнение с NULL с использованием оператора равенства (=) всегда возвращает неизвестное значение, даже если связь не установлена. Второй запрос всегда будет возвращать пустой результат.

Выражения сравнения с пустой коллекцией

Выражение сравнения IS [NOT] EMPTY проверяет, нет ли в выражении пути с коллекцией значений элементов. Другими словами, он проверяет, установлено ли отношение со значением коллекции.

Если выражение пути со значением коллекции NULL, пустое выражение сравнения коллекции имеет значение NULL.

Вот пример, который находит все заказы, которые не имеют позиций:

SELECT o
FROM CustomerOrder o
WHERE o.lineItems IS EMPTY

Выражения к членам коллекции

Выражение члена коллекции [NOT] MEMBER [OF] определяет, является ли значение членом коллекции. Значение и члены коллекции должны иметь одинаковый тип.

Если выражение пути с коллекцией или с одним значением неизвестно, выражение члена коллекции неизвестно. Если выражение пути со значением коллекции обозначает пустую коллекцию, выражение члена коллекции имеет значение FALSE.

Ключевое слово OF является необязательным.

В следующем примере проверяется, является ли позиция частью заказа:

SELECT o
FROM CustomerOrder o
WHERE :lineItem MEMBER OF o.lineItems

Подзапросы

Подзапросы могут использоваться в предложении WHERE или HAVING запроса. Подзапросы должны быть заключены в круглые скобки.

Следующий пример находит всех клиентов, которые разместили более десяти заказов:

SELECT c
FROM Customer c
WHERE (SELECT COUNT(o) FROM c.orders o)> 10

Подзапросы могут содержать выражения EXISTS, ALL и ANY.

  • Выражения EXISTS: выражение [NOT] EXISTS используется с подзапросом и имеет значение true, только если результат подзапроса состоит из одного или нескольких значений. В противном случае false.

    Следующий пример находит всех сотрудников, чьи супруги также являются сотрудниками:

    SELECT DISTINCT emp
    FROM Employee emp
    WHERE EXISTS (
        SELECT spouseEmp
        FROM Employee spouseEmp
        WHERE spouseEmp = emp.spouse)
  • Выражения ALL и ANY: выражение ALL используется с подзапросом и имеет значение true, если все значения, возвращаемые подзапросом, являются истинными или если подзапрос пуст.

    Выражение ANY используется с подзапросом и является истинным, если некоторые из значений, возвращаемых подзапросом, являются истинными. Выражение ANY является ложным, если результат подзапроса пуст или если все возвращённые значения являются ложными. Ключевое слово SOME является синонимом ANY.

    Выражения ALL и ANY используются с операторами сравнения =, <, , >, >= и <>.

    Следующий пример находит всех сотрудников, чьи зарплаты выше, чем зарплаты менеджеров в отделе сотрудников:

    SELECT emp
    FROM Employee emp
    WHERE emp.salary > ALL (
        SELECT m.salary
        FROM Manager m
        WHERE m.department = emp.department)

Функциональные выражения

Язык запросов включает несколько строковых, арифметических функций и функций даты и времени, которые могут использоваться в предложениях SELECT, WHERE или HAVING запроса. Функции перечислены в таблице 42-4, таблице 42-5 и таблице 42-6.

В таблице 42-4 аргументы start и length имеют тип int и обозначают позиции в String аргумент. Нумерация позиций в строке начинается с 1.

Таблица 42-4 Строковые выражения

Синтаксис функции

Возвращаемый тип

CONCAT(String, String)

String

LENGTH(String)

int

LOCATE(String, String [, start])

int

SUBSTRING(String, start, length)

String

TRIM([[LEADING|TRAILING|BOTH] char) FROM] (String)

String

LOWER(String)

String

UPPER(String)

String

Функция CONCAT объединяет две строки в одну строку.

Функция LENGTH возвращает длину строки в символах в виде целого числа.

Функция LOCATE возвращает позицию указанной строки в строке. Эта функция возвращает первую позицию, в которой строка была найдена, как целое число. Первый аргумент — это строка, которую нужно найти. Второй аргумент — это строка, в которой выполняется поиск. Необязательный третий аргумент — это целое число, представляющее позицию в строке из второго аргумента, с которой должен выполняться поиск. По умолчанию LOCATE начинает поиск с начала строки из второго аргумента. То есть с 1. Если строка не была найдена, LOCATE возвращает 0.

Функция SUBSTRING возвращает строку, которая является подстрокой первого аргумента, основываясь на начальной позиции и длине.

Функция TRIM обрезает указанный символ от начала и/или конца строки. Если символ не указан, TRIM удаляет пробельные символы из строки. Если используется необязательная спецификация LEADING, TRIM удаляет только начальные символы из строки. Если используется необязательная спецификация TRAILING, TRIM удаляет только завершающие символы из строки. По умолчанию используется значение BOTH, которое удаляет начальные и конечные символы из строки.

Функции LOWER и UPPER преобразуют строку в нижний или верхний регистр соответственно.

В таблице 42-5 аргумент number может быть int, float или double.

Таблица 42-5 Арифметические выражения

Синтаксис функции

Возвращаемый тип

ABS(number)

int, float, or double

MOD(int, int)

int

SQRT(double)

double

SIZE(Collection)

int

Функция ABS принимает числовое выражение и возвращает число того же типа, что и аргумент.

Функция MOD возвращает остаток от деления первого аргумента на второй.

Функция SQRT возвращает квадратный корень из числа.

Функция SIZE возвращает целое число — количество элементов в данной коллекции.

В таблице 42-6 функции даты/времени возвращают дату, время или метку времени на сервере базы данных.

Таблица 42-6 Выражение даты/времени

Синтаксис функции

Возвращаемый тип

CURRENT_DATE

java.sql.Date

CURRENT_TIME

java.sql.Time

CURRENT_TIMESTAMP

java.sql.Timestamp

Выражения Case

Выражения Case изменяются в зависимости от условия, аналогично ключевому слову case Java. Ключевое слово CASE указывает начало выражения Case, а выражение завершается ключевым словом END. Ключевые слова WHEN и THEN определяют отдельные условия, а ключевое слово ELSE определяет условие по умолчанию, если не выполняется ни одно из других условий.

Следующий запрос выбирает имя человека и условную строку в зависимости от подтипа объекта Person. Если подтипом является Student, возвращается строка kid. Если подтипом является Guardian или Staff, возвращается строка adult. Если сущность является другим подтипом Person, возвращается строка unknown:

SELECT p.name
CASE TYPE(p)
    WHEN Student THEN 'kid'
    WHEN Guardian THEN 'adult'
    WHEN Staff THEN 'adult'
    ELSE 'unknown'
END
FROM Person p

Следующий запрос устанавливает скидку для различных типов клиентов. Покупатели золотого уровня получают скидку 20%, серебряного — 15%, бронзового — 10%, а все остальные получают скидку 5%:

UPDATE Customer c
SET c.discount =
    CASE c.level
        WHEN 'Gold' THEN 20
        WHEN 'SILVER' THEN 15
        WHEN 'Bronze' THEN 10
        ELSE 5
    END

Значения NULL

Если ссылки указывает на несуществующий в персистентном хранилище объект, значением ссылки будет NULL. Для условных выражений, содержащих NULL, язык запросов использует семантику, определённую SQL92. Вкратце, эта семантика заключается в следующем.

  • Если операция сравнения или арифметическая операция имеют неизвестное значение, она возвращает значение NULL.

  • Два значения NULL не равны. Сравнение двух значений NULL даёт неизвестное значение.

  • Проверка IS NULL преобразует персистентное поле NULL или однозначное поле отношения в TRUE. Проверка IS NOT NULL преобразует их в FALSE.

  • Логические операторы и условные проверки используют трёхзначную логику, определённую в таблице 42-7 и таблице 42-8. (В этих таблицах T означает TRUE, F — FALSE, а U — неизвестно.)

Таблица 42-7 Логика оператора AND

AND

T

F

U

T

T

F

U

F

F

F

F

U

U

F

U

Таблица 42-8 Логика оператора OR

OR

T

F

U

T

T

T

T

F

T

F

U

U

T

U

U

Семантика равенства

На языке запросов можно сравнивать только значения одного типа. Однако из этого правила есть одно исключение: можно сравнивать точные и приблизительные числовые значения. При таком сравнении необходимое преобразование типов соответствует правилам Java.

Язык запросов обрабатывает сравниваемые значения, как если бы они были типами Java, а не как если бы они представляли типы в хранилище данных. Например, персистентное поле, которое может быть целым числом или NULL, должно быть обозначено как объект Integer, а не как примитив int. Это обозначение является обязательным, поскольку объект Java может быть NULL, а примитив — нет.

Две строки равны, только если они содержат одинаковую последовательность символов. Пробелы в начале и конце имеют значение. Например, строки 'abc' и 'abc ' не равны.

Два объекта сущности одного и того же типа схемы абстракций равны, только если их первичные ключи имеют одинаковое значение. Таблица 42-9 показывает логику оператора отрицания, а таблица 42-10 показывает истинные значения условных тестов.

Таблица 42-9 Логика оператора NOT

NOT Value

Значение

T

F

F

T

U

U

Таблица 42-10 Условный тест

Условный тест

T

F

U

Выражение IS TRUE

T

F

F

Выражение IS FALSE

F

T

F

Выражение неизвестно

F

F

T

Выражение SELECT

Предложение SELECT определяет типы объектов или значений, возвращаемых запросом.

Здесь рассматриваются следующие темы:

Возвращаемые типы

Возвращаемый тип предложения SELECT определяется типами результатов выражений select, содержащихся в нём. Если используется несколько выражений, результатом запроса является Object[], а элементы в массиве соответствуют порядку выражений в предложении SELECT с соответствующими каждому выражению типами.

Предложение SELECT не может указывать выражение со значением коллекции. Например, предложение SELECT p.teams недопустимо, поскольку teams является коллекцией. Однако предложение в следующем запросе является допустимым, поскольку t является отдельным элементом коллекции teams:

SELECT t
FROM Player p, IN (p.teams) t

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

SELECT c.name, c.country.name
FROM customer c
WHERE c.lastname = 'Coss' AND c.firstname = 'Roxane'

Этот запрос возвращает список элементов Object[]. Первый элемент массива представляет собой строку, обозначающую имя клиента, а второй элемент массива — строку, обозначающую название страны клиента.

Результат запроса может быть результатом вычисления статистической функции, указанной в таблице 42-11.

Таблица 42-11. Агрегатные функции в выражениях Select

Название

Возвращаемый тип

Описание

AVG

Double

Возвращает среднее значение полей

COUNT

Long

Возвращает общее количество результатов

MAX

Тип поля

Возвращает максимальное значение в наборе результатов

MIN

Тип поля

Возвращает минимальное значение в наборе результатов

SUM

Long (для интегральных полей)

Double (для полей с плавающей точкой)

BigInteger (для полей BigInteger)

BigDecimal (для полей BigDecimal)

Возвращает сумму всех значений в наборе результатов

Для выбора метода запроса с агрегатной функцией (AVG, COUNT, MAX, MIN или SUM) в предложении SELECT применяются следующие правила.

  • Функции AVG, MAX, MIN и SUM возвращают null, если есть нет значений, к которым функция может быть применена.

  • Функция COUNT возвращает 0, если нет значений, к которым функция может быть применена.

В следующем примере возвращается среднее количество заказов:

SELECT AVG(o.quantity)
FROM CustomerOrder o

В следующем примере возвращается общая стоимость товаров, заказанных Roxane Coss:

SELECT SUM(l.price)
FROM CustomerOrder o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Coss' AND c.firstname = 'Roxane'

В следующем примере возвращается общее количество заказов:

SELECT COUNT(o)
FROM CustomerOrder o

В следующем примере возвращается общее количество товаров с ценами в заказе Hal Incandenza:

SELECT COUNT(l.price)
FROM CustomerOrder o JOIN o.lineItems l JOIN o.customer c
WHERE c.lastname = 'Incandenza' AND c.firstname = 'Hal'

Ключевое слово DISTINCT

Ключевое слово DISTINCT исключает повторяющиеся возвращаемые значения. Если запрос возвращает java.util.Collection, который разрешает дублирование, необходимо указать ключевое слово DISTINCT, чтобы исключить дубликаты.

Выражения Constructor

Выражения конструктора позволяют вам возвращать объекты Java, которые хранят элемент результата запроса вместо Object[].

Следующий запрос создаёт объект CustomerDetail для Customer, соответствующий предложению WHERE. CustomerDetail хранит имя клиента и название страны клиента. Таким образом, запрос возвращает List объектов CustomerDetail:

SELECT NEW com.example.CustomerDetail(c.name, c.country.name)
FROM customer c
WHERE c.lastname = 'Coss' AND c.firstname = 'Roxane'

Выражение ORDER BY

Как следует из названия, предложение ORDER BY упорядочивает значения или объекты, возвращаемые запросом.

Если предложение ORDER BY содержит несколько элементов, последовательность элементов слева направо определяет упорядоченность от максимального к минимальному.

Ключевое слово ASC указывает восходящий порядок, значение по умолчанию, а ключевое слово DESC указывает нисходящий порядок.

При использовании предложения ORDER BY предложение SELECT должно возвращать упорядоченный набор объектов или значений. Нельзя упорядочивать значения или объекты для значений или объектов, не возвращаемых предложением SELECT. Например, следующий запрос является допустимым, поскольку в предложении ORDER BY используются объекты, возвращаемые предложением SELECT:

SELECT o
FROM Customer c JOIN c.orders o JOIN c.address a
WHERE a.state = 'CA'
ORDER BY o.quantity, o.totalcost

Следующий пример недопустим, поскольку в предложении ORDER BY используется значение, не возвращаемое предложением SELECT:

SELECT p.product_name
FROM CustomerOrder o, IN(o.lineItems) l JOIN o.customer c
WHERE c.lastname = 'Faehmel' AND c.firstname = 'Robert'
ORDER BY o.quantity

Выражения GROUP BY и HAVING

Предложение GROUP BY позволяет группировать значения в соответствии с набором свойств.

Следующий запрос группирует клиентов по их стране и возвращает количество клиентов по стране:

SELECT c.country, COUNT(c)
FROM Customer c GROUP BY c.country

Предложение HAVING используется с предложением GROUP BY для дальнейшей фильтрации возвращаемого результата запроса.

Следующий запрос группирует заказы по статусу их клиента и возвращает статус клиента плюс среднее значение totalPrice для всех заказов, где соответствующие клиенты имеют одинаковый статус. Кроме того, он рассматривает только клиентов со статусом 1, 2 или 3, поэтому заказы других клиентов не учитываются:

SELECT c.status, AVG(o.totalPrice)
FROM CustomerOrder o JOIN o.customer c
GROUP BY c.status HAVING c.status IN (1, 2, 3)

Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)