Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2013_1 / КСТ / Разработка веб-приложений.pdf
Скачиваний:
160
Добавлен:
23.02.2015
Размер:
2.74 Mб
Скачать

Управление согласно полям связи

SELECT DISTINCT p

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

Результат: игроки, которые участвуют в определённом спорте.

Описание:хранимаяобластьспортапринадлежитсущностиLeague.Чтобыдостичь поля sport, запрос должен сначала перейти от сущности Player до Team (p.teams) и затем от Team до сущности League (t.league). Поскольку поле league отношения не является коллекцией, оно может следовать за хранимым полем sport.

13.6.Запросы с другими условными выражениями

Каждая статья WHERE может определить условное выражение в нескольких вариантах. В предшествующих примерах условные выражения являются выражениями сравнения, которые тестируются на равенство. Следующие примеры демонстрируют некоторые другие варианты условных выражений.

Запросы LIKE

SELECT p

FROM Player p

WHERE p.name LIKE ’Mich%’

Результат: все игроки, чьи имена начинают с Mich.

Описание: выражение LIKE использует символы шаблона, чтобы искать строки, которые соответствуют образцу. В этом случае запрос использует выражение LIKE и шаблон «%», чтобы находить всех игроков, чьи имена начинаются со строки Mich. Например, имена Michael и Michelle оба соответствуют образцу шаблона.

Выражение IS NULL

SELECT t FROM Team t

WHERE t.league IS NULL

Результат: все команды, не связанные с лигой.

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

Выражение IS EMPTY

SELECT p FROM Player p

WHERE p.teams IS EMPTY

Результат: все игроки, не принадлежащие командам.

Описание: поле teams отношения сущности Player является коллекцией. Если игрок не принадлежит команде, тогда коллекция teams будет пустой, условным выра-

жением является TRUE.

156

Выражение BETWEEN

SELECT DISTINCT p FROM Player p

WHERE p.salary BETWEEN :lowerSalary AND :higherSalary

Результат: игроки, чей фонд зарплаты находится в пределах определённого диапазона.

Описание: это выражение BETWEEN имеет три арифметических выражения: хранимое поле (p.salary) и два входных параметра (:lowerSalary и :higherSalary). Следующее выражение является эквивалентом BETWEEN выражению:

p.salary >= :lowerSalary AND p.salary <= :higherSalary

Операторы сравнения

SELECT DISTINCT p1

FROM Player p1, Player p2

WHERE p1.salary > p2.salary AND p2.name = :name

Результат: все игроки, чей фонд зарплаты выше, чем жалованье игрока с определённым именем.

Описание: статья FROM объявляет две переменные (p1 и p2) того же самого типа (Player). Две переменных нужны, поскольку статья WHERE сравнивает жалованье одного игрока (p2) с другими игроками (p1).

13.7.Изменение и удаление группы сущностей

Следующие примеры показывают, как использовать выражения UPDATE и DELETE в запросах. UPDATE и DELETE действуют на многие сущности согласно условию, установленному в статье WHERE. Статья WHERE в запросе UPDATE и DELETE следует тем же правилам, что и в запросе SELECT.

Запрос UPDATE

UPDATE Player p

SET p.status = ’inactive’

WHERE p.lastPlayed < :inactiveThresholdDate

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

Запрос DELETE

DELETE

FROM Player p

WHERE p.status = ’inactive’ AND p.teams IS EMPTY

Описание: Этот запрос удаляет всех неактивных игроков, которые не зачислены в команды.

157

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

Вданном разделе описывается синтаксис языка запроса, как определено в спецификации Java Persistence.

13.8.1.Символы BNF

 

Таблица 13.1

 

 

Символ

Описание

::=

Элемент слева от символа определен справа

*

Выражение слева может входить нуль или более раз

{...}

Конструкция в пределах фигурных скобок образует группу

[...]

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

|

Исключительное ИЛИ

ЖИРНЫЙ

Ключевое слово (заглавные буквы на диаграмме BNF,

шрифт

не регистро-чувствительные ключевые слова)

Интервал

Символ интервала может быть пробелом, горизонтальной

 

табуляцией или переводом строки

13.8.2. BNF-грамматика языка Java Persistence Query Language

Полная диаграмма 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::=

158

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 |

159

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

160

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 |

161

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. Каждый по-

следующий символ в последовательности должен быть правильным символом (буква, цифра, $, _) в идентификаторе Java. Знак вопроса (?) — зарезервированный символ в языке запросов и не может быть использован в идентификаторе. Идентификаторы запроса — регистро-чувствительные с двумя исключениями, касающимися ключевых слов языка запросов и SQL.

162

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

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

Список ключевых слов языка запроса

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.

13.8.3. Идентификационные переменные отношений

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

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

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

объявленную переменную p:

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

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

163

два запроса. Первый запрос возвращает всех игроков, принадлежащих или не принадлежащих команде:

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

Переменная идентификации всегда определяет ссылку на единственное значе-

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

два типа деклараций: переменная диапазона (Range Variable) и элемент коллекции.

Декларации Range Variable

Чтобы объявлять переменную идентификации как абстрактный тип схемы, вы

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

примере переменная идентификации p представляет абстрактную схему с именем

Player:

FROM Player p

Переменная декларация диапазона может включить дополнительный оператор AS:

FROM Player AS p

В большинстве случаев, чтобы получить объекты, вы используете выражения

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

Если запрос сравнивает многочисленные значения той же самой абстрактной

схемы, тогда статья FROM должна объявить многочисленные переменные идентифи-

кации для абстрактной схемы, например:

FROM Player p1, Player p2

Декларации элемента коллекции

В отношении «один-ко-многим» множественная сторона состоит из коллекции

сущностей. Переменная идентификации может представить элемент этого набора. Для того, чтобы иметь доступ к элементу набора, выражение пути в декларации пере-

менной включает переходы через отношения в абстрактной схеме. Поскольку выра-

жение пути может быть основано на другом выражении пути, навигация может про-

смотреть несколько связей.

Декларация элемента коллекции должна включать оператор IN, но можно опу-

стить дополнительный оператор AS.

В следующем примере сущность представляется абстрактной схемой Player и

имеет поле отношения с именем teams. Переменная идентификации была названа t и представляет единственный элемент набора teams.

FROM Player p, IN (p.tea ms) t

164

Присоединения

Оператор 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 Order o LEFT JOIN o.customer c

FETCH JOIN является операцией соединения, которая возвращает связанные

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

SELECT d

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

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

Выражения пути — важная часть синтаксиса языка запросов. Во-первых, они

определяют навигацию через отношения в абстрактных схемах. Эта часть определяет

результирующую область просмотра и результат запроса. Во-вторых, они появляются в основных операторах запроса 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

165

Ниже статья WHERE содержит single_valued_path_expression. Переменная t

и league — отношения single-valued, переменная sport — хранимое поле отношения league.

SELECT DISTINCT p

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

Ниже статья WHERE содержит collection_valued_path_expression. Переменная p — идентифицирующая переменная, а teams обозначает поле collection-valued relationship.

SELECT DISTINCT p FROM Player p

WHERE p.teams IS EMPTY

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

Тип выражений пути является типом объекта, представленным конечным эле-

ментом, который может быть:

хранимым полем;

полем отношения с одним значением (Single-valued);

полем отношения с коллекцией значений (Collection-valued).

Например, тип выражения p.salary double, потому что тип последнего поля salary есть double.

В выражении p.teams последний элемент — коллекция, поэтому тип выражения — коллекция сущностей.

Навигация

Выражение пути позволяет производить навигацию по сущностям отношения.

Последний элемент выражения определяет разрешенную навигацию. Если выражение содержит поле отношения Single-valued, просматриваются объекты, указываемые полем. Однако выражения не могут просматривать хранимые поля или поля коллек-

ций Collection-valued. Например, выражение p.teams.league.sport — правильное, так

как teams — поле отношения Collection-valued. Для указания поля sport статья FROM

может определить переменную идентификации с именем t для поля teams.

FROM Player AS p, IN (p.teams) t WHERE t.league.sport = ’soccer’

13.8.5. Статья WHERE

ОпцияWHERE задаётусловноевыражение,ограничивающеезначения,возвращаемые запросом. Запрос возвращает все значения, соответствующие истинному вы-

ражению. Если статья WHERE отсутствует, то возвращаются все значения. Синтаксис

опции WHERE следующий:

where_clause ::= WHERE conditional_expression

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

литералов: String, numeric, Boolean, Enum. Можно использовать именованные и позиционные параметры, все допустимые в Java арифметические и логические опе-

рации и сравнения аргументов. Кроме простых условий, можно использовать опера-

ции LIKE, BETWEEN и IN. Для проверки на пустое множество используется операция

IS EMPTY.

SELECT o

FROM Order o

WHERE o.lineItems IS EMPTY

166

Для проверки принадлежности множеству есть операция MEMBER OF, например:

SELECT o

FROM Order o

WHERE :lineItem MEMBER OF o.lineItems

Допускается использовать запросы в условиях:

SELECT c

FROM Customer c

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

SELECT DISTINCT emp

FROM Employee emp

WHERE EXISTS (

SELECT spouseEmp

FROM Employee spouseEmp

WHERE spouseEmp = emp.spouse)

SELECT emp

FROM Employee emp

WHERE emp.salary > ALL ( SELECT m.salary FROM Manager m

WHERE m.department = emp.department)

В табл. 13.2 определены функции различных типов.

Таблица 13.2

Функции языка запросов

 

 

 

Функция

Возвращаемое

значение

 

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

 

 

ABS(number)

int, float, or double

MOD(int, int)

int

SQRT(double)

double

SIZE(Collection)

int

 

 

CURRENT_DATE

java.sql.Date

CURRENT_TIME

java.sql.Time

CURRENT_TIMESTAMP

java.sql.Timestamp

167

Выражение CASE

Выражение CASE аналогично оператору CASE языка Java и позволяет произ-

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

от типа сущности Person:

SELECT p.name CASE TYPE(p)

WHEN Student THEN ’kid’ WHEN Guardian THEN ’adult’ WHEN Staff THEN ’adult’

ELSE ’unknown’ END

FROM Person p

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

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;

булевские операции и сравнения используют трехзначную логику со значе-

ниями TRUE, FALSE и UNKNOW (T, F, U). Для операндов T, F результаты совпадают с классической логикой;

для операции AND, если один из операндов — U, результат будет U;

для операции OR, если один из операндов не T, а второй — U, результат бу-

дет U;

для операции NOT результат для операнда U есть U;

для значения целого поля NULL возвращается объект класса Integer со значе-

нием NULL, а не базового типа int, в котором нет значения NULL.

13.8.6. Статья SELECT

Возвращаемый результат определяется выражением внутри статьи. Если ис-

пользуется несколько выражений, то результат запроса — массив Object[ ] с элементами, соответствующими порядку выражений в статье SELECT и их типами. В SELECT нельзязапрашиватьколлекции.Например,SELECT p.teams недопустимоевыражение,

так как teams — коллекция. Но можно запрашивать элемент коллекции, например:

SELECT t

FROM Player p, IN (p.teams) t

168

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

SELECT c.name, c.country.name

FROM customer c

WHERE c.lastname = ’Coss’ AND c.firstname = ’Roxane’

Он возвращает список элементов Object[ ], где первый элемент — имя клиента, вто-

рой — название страны.

Агрегатные функции в операциях выбора

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

ведённой в таблице 13.3.

 

 

Таблица 13.3

 

Агрегатные функции

 

 

 

Имя

Тип значения

Описание

AVG

Double

Среднее значение поля

COUNT

Long

Количество результатов

MAX

Тип поля

Максимальное значение поля

MIN

Тип поля

Минимальное значение поля

SUM

Long (для целых),

Сумма всех значений поля в

 

Double (для дробных),

наборе

 

BigInteger. BigDecimal

 

Если результирующий набор пуст, то для AVG, COUNT, MAX, MIN или SUM возвращается NULL, для COUNT — 0.

Примеры

Среднее значение поля quantity сущности Order:

SELECT AVG(o.quantity)

FROM Order o

Сумма значений поля price в пунктах lineItems заказа для сущности Order с име-

нем Roxane Coss:

SELECT SUM(l.price)

FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = ’Coss’ AND c.firstname = ’Roxane’

Число элементов в наборе Order:

SELECT COUNT(o)

FROM Order o

Число пунктов заказов, у которых есть стоимость, для клиента Hal Incandenza в наборе Order:

SELECT COUNT(l.price)

FROM Order o JOIN o.lineItems l JOIN o.customer c WHERE c.lastname = ’Incandenza’ AND c.firstname = ’Hal’

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

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

то можно использовать в операторе SELECT ключевое слово DISTINCT.

169

Выражения-конструкторы

Выражения-конструкторы создают новые экземпляры объектов, соответствую-

щие опции запроса WHERE. В приведённом ниже примере создаются экземпляры CustomerDetail для Customer. CustomerDetail хранит имя клиента и название страны

проживания. Запрос возвращает список List экземпляров CustomerDetail.

SELECT NEW com.xyz.CustomerDetail(c.name, c.country.name)

FROM customer c

WHERE c.lastname = ’Coss’ AND c.firstname = ’Roxane’

Опция ORDER BY

Опция позволяет упорядочить возвращаемый запросом набор значений или

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

сортировки. Опция ASC определяет прямой (по умолчанию), а DESC — обратный по-

рядок сортировки. Нельзя сортировать запросы, не возвращающие наборы значений. Пример правильного запроса:

SELECT o

FROM Customer c JOIN c.orders o JOIN c.address a WHERE a.state = ’CA’

ORDER BY o.quantity, o.totalcost

Пример неправильного запроса (в запросе нет значения quantity):

SELECT p.product_name

FROM Order o, IN(o.lineItems) l JOIN o.customer c WHERE c.lastname = ’Faehmel’ AND c.firstname = ’Robert’ ORDER BY o.quantity

Опция GROUP BY

Опция GROUP BY используется для группировки значений свойств набора. Следующий запрос группирует клиентов по стране и возвращает число клиентов в

странах:

SELECT c.country, COUNT(c)

FROM Customer c GROUP BY c.country

Опция HAVING

Опция HAVING используется совместно с GROUP BY для ограничений значе-

ний результата запроса. Следующий пример запроса группирует заказы по статусу их

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

SELECT c.status, AVG(o.totalPrice) FROM Order o JOIN o.customer c

GROUP BY c.status HAVING c.status IN (1, 2, 3)

13.9. Примеры запросов

Java Persistence Query Language

В п. 1.4 данной работы был приведён пример приложения для работы с СУБД PostgreSQL, в котором использовалась техника запросов Criteria API, описанная ниже в главе 14. Изменения, которые необходимо проделать в тексте описания класса Org_ techFacade для использования запросов JPQL, приведены ниже. Для сравнения кода старый текст закомментирован, что позволяет оценить детали сходства и различия.

170

Файл Org_techFacade.java

Класс-посредник (фасад) для связывания бинов сущности и вида с хранили-

щем данных в БД: package EntityGGIS;

import dbGGIS.Org_tech; import java.util.List; import javax.ejb.Stateless;

import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query;

//import javax.persistence.criteria.CriteriaQuery; //import javax.persistence.criteria.Root;

/**

*

* @author cyx */ @Stateless

public class Org_techFacade { @PersistenceContext(unitName = "GGISCyxPU") private EntityManager em;

public void create(Org_tech org_Tech) { em.persist(org_Tech);

}

public void edit(Org_tech org_Tech) { em.merge(org_Tech);

}

public void remove(Org_tech org_Tech) { em.remove(em.merge(org_Tech));

}

public Org_tech find(Object id) { return em.find(Org_tech.class, id);

}

public List<Org_tech> findAll() {

//CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); //cq.select(cq.from(Org_tech.class));

//return em.createQuery(cq).getResultList(); return em.createQuery("SELECT ot FROM Org_tech ot")

//.setMaxResults(10)

.getResultList();

}

public List<Org_tech> findRange(int[] range) {

//CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); //cq.select(cq.from(Org_tech.class));

171

//Query q = em.createQuery(cq); //q.setMaxResults(range[1] - range[0]); //q.setFirstResult(range[0]);

//return q.getResultList();

Query q = em.createQuery("SELECT ot FROM Org_tech ot"); q.setMaxResults(range[1] - range[0]); q.setFirstResult(range[0]);

return q.getResultList();

}

public int count() {

//CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); //Root<Org_tech> rt = cq.from(Org_tech.class); //cq.select(em.getCriteriaBuilder().count(rt));

//Query q = em.createQuery(cq);

//return ((Long) q.getSingleResult()).intValue();

Query q = em.createQuery("SELECT count(ot) FROM Org_tech ot"); return ((Long) q.getSingleResult()).intValue();

}

}

Читателю предстоит сравнить обе техники доступа к базам данных и сделать выбор при разработке своих приложений. Но все-таки следует заметить следующее:

язык JPQL более близок к стандарту языка SQL, принятому в реляционных

СУБД;

тексты на языке JPQL более компактны и естественны;

для использования JPQL необходимо знание языка SQL, в Criteria API сам за-

прос на языке SQL генерируется вызовом некоторых методов;

функциональность обоих инструментов эквивалентна друг другу.

172

Соседние файлы в папке КСТ