*
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
В этом разделе обсуждается синтаксис языка запросов, определённый в спецификации Java Persistence API 2.0, доступной по ссылке http://jcp.org/en/jsr/detail?id=317
. Многое из следующего материала перефразирует или прямо цитирует спецификацию.
Здесь рассматриваются следующие темы:
Таблица 42-1 описывает символы BNF, используемые в этой главе.
Таблица 42-1 Обзор символов BNF
Символ |
Описание |
|
Элемент слева от символа определяется конструкциями справа. |
|
Предыдущая конструкция может встречаться ноль или более раз. |
|
Конструкции в фигурных скобках сгруппированы вместе. |
|
Конструкции в квадратных скобках не являются обязательными. |
|
Исключающее |
|
Ключевое слово. Хотя в диаграмме BNF они указаны прописными, ключевые слова не чувствительны к регистру. |
Символ пробела |
Символом пробела может быть пробел, горизонтальная табуляция или перевод строки. |
Вот полная диаграмма 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
определяет область запроса путём объявления идентификационных переменных.
Здесь рассматриваются следующие темы:
Идентификатор — это последовательность из одного или нескольких символов. Правила к именам идентификаторов такие же, как и к идентификаторам в 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
определяет условное выражение, которое фильтрует значения, возвращаемые запросом. Запрос возвращает все соответствующие значения из хранилища данных, для которого значение условного выражения 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. Порядок приоритетов языка запросов
Тип |
Порядок приоритета |
Навигация |
|
Арифметические |
|
Сравнения |
|
Логические |
|
Выражение 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
определяет, принадлежит ли строка к набору строковых литералов или число принадлежит к набору числовых значений.
Выражение пути должно иметь строковое или числовое значение. Если выражение пути имеет значение NULL
, значение выражения IN
неизвестно.
В следующем примере выражение равно TRUE
, если страна UK
, но FALSE
, если страна Peru
:
o.country IN ('UK', 'US', 'France')
Также могут использоваться входные параметры:
o.country IN ('UK', 'US', 'France', :country)
Выражение LIKE
определяет, соответствует ли шаблон подстановки строке.
Выражение пути должно иметь строковое или числовое значение. Если это значение равно NULL
, значение выражения LIKE
неизвестно. Значением шаблона является строковый литерал, который может содержать символы подстановки. Подстановочный знак (_
) обозначает любой отдельный символ. Подстановочный знак процента (%
) представляет собой ноль или более символов. Предложение ESCAPE
определяет escape-символ для символов подстановки в значении шаблона. Таблица 42-3 показывает некоторые примеры выражений LIKE
.
Таблица 42-3 Примеры выражения LIKE
Выражение |
TRUE |
FALSE |
|
|
|
|
|
|
|
|
|
|
|
|
Выражение сравнения с 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
объединяет две строки в одну строку.
Функция 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
принимает числовое выражение и возвращает число того же типа, что и аргумент.
Функция MOD
возвращает остаток от деления первого аргумента на второй.
Функция SQRT
возвращает квадратный корень из числа.
Функция SIZE
возвращает целое число — количество элементов в данной коллекции.
В таблице 42-6 функции даты/времени возвращают дату, время или метку времени на сервере базы данных.
Таблица 42-6 Выражение даты/времени
Синтаксис функции |
Возвращаемый тип |
|
|
|
|
|
|
Выражения 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
, язык запросов использует семантику, определённую 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 |
Выражение |
T |
F |
F |
Выражение |
F |
T |
F |
Выражение неизвестно |
F |
F |
T |
Предложение 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
, 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
исключает повторяющиеся возвращаемые значения. Если запрос возвращает java.util.Collection
, который разрешает дублирование, необходимо указать ключевое слово DISTINCT
, чтобы исключить дубликаты.
Выражения конструктора позволяют вам возвращать объекты 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
содержит несколько элементов, последовательность элементов слева направо определяет упорядоченность от максимального к минимальному.
Ключевое слово 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
позволяет группировать значения в соответствии с набором свойств.
Следующий запрос группирует клиентов по их стране и возвращает количество клиентов по стране:
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)
Назад | Вперёд | Содержание |