EJB3-QL은 HQL, native Hibernate Query Language에 의해 크게 영감을 받았다. 그러므로 둘 다 SQL에 아주 가깝지만, 데이터베이스 스키마에 이식 가능하고 독립적이다. HQL에 익숙한 사람들은 EJB-QL을 사용하는데 별다른 문제점을 갖지 않는다. 실제로 당신은 EJB-QL과 HQL 질의들에 대해 동일한 질의 API를 사용한다. 하지만 이식가능한 EJB3 어플리케이션들은 EJB-QL에 충실해야 하거나 유사한 벤더 확장들이 필요하다.
질의들은 자바 클래스들과 프로퍼티들의 이름들을 제외하면 대소문자를 구분하지 않는다. 따라서 SeLeCT가 sELEct과 동일하며 SELECT과 동일하지만 org.hibernate.eg.FOO은 org.hibernate.eg.Foo과 같지 않고 foo.barSet은 foo.BARSET과 같지 않다.
이 매뉴얼은 소문자 EJBQL 키워드들을 사용한다. 몇몇 사용자들은 보다 가독성이 있는 대문자 키워드들을 가진 질의들을 사용하지만, 우리는 자바 코드 속에 삽입시킬 때 이 컨벤션이 추하다는 점을 발견한다.
가능 간단한 가능한 EJB-QL 질의는 다음 형식이다:
select c from eg.Cat c
이것은 단순히 eg.Cat 클래스의 모든 인스턴스들을 반환한다. HQL과는 달리, select 절은 EJB-QL에서 옵션이 아니다. 우리는 클래스 이름을 수식할 필요가 없다. 왜냐하면 엔티티 이름이 디폴트로 수식되지 않은 클래스 이름(@Entity)이기 때문이다. 따라서 우리는 거의 항상 단지 다음과 같이 작성한다:
select c from Cat c
당신이 인지했을 수도 있듯이 당신은 클래스들에 alias들을 할당할 수 있으며, as 키워드는 옵션이다. 한 개의 alias는 질의의 다른 부분들 내에서 Cat을 참조하는 것을 당신에게 허용해준다.
select cat from Cat as cat
여러 개의 클래스들이 하나의 카티젼 곲 또는 "크로스" 조인으로 귀결되어 나타날 수도 있다.
select form, param from Formula as form, Parameter as param
로컬 변수들에 대한 자바 명명법 표준과 일치되게끔 초문자 첫 글자를 사용하여 질의 alias를 명명하는 것은 좋은 실례로 간주된다(예를들면. domesticCat).
당신은 또한 join을 사용하여, alias들을 연관된 엔티티들에 할당할 수 있거나, 심지어 값들을 가진 하나의 콜렉션의 요소들에 할당할 수도 있다.
select cat, mate, kitten from Cat as cat
inner join cat.mate as mate
left outer join cat.kittens as kittenselect cat from Cat as cat left join cat.mate.kittens as kittens
지원되는 join 타입들은 ANSI SQL로부터 빌려왔다
inner join
left outer join
inner join, left outer join 구조체는 생략하여 쓰일수도 있다.
select cat, mate, kitten from Cat as cat
join cat.mate as mate
left join cat.kittens as kitten게다가, 하나의 "fetch" join은 연관들 또는 값들을 가진 콜렉션들이 한 개의 select를 사용하여 그것들의 부모 객체들에 따라 초기화 되는 것을 허용해준다. 이것은 콜렉션의 경우에 특히 유용하다. 그것은 연관들과 콜렉션 매핑 메카데이터에서 페칭 옵션들을 효과적으로 오버라이드 시킨다. 추가 정보는 Hibernate 참조 안내서의 퍼포먼스 장을 보라.
select cat from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens하나의 fetch join은 대개 한 개의 alias를 할당할 필요가 없다. 왜냐하면 연관된 객체들이 where 절(또는 어떤 다른 절) 속에서 사용되지 않을 것이기 때문이다. 또한 연관된 객체들은 질의 결과 셋들 속에서 직접 반환되지 않는다. 대신에, 그것들은 부모 객체를 통해 접근될 수도 있다. 우리가 alias를 필요로 하는 유일한 이유는 우리가 추가적인 콜렉션을 재귀적으로 조인 페칭할 경우이다:
select cat from Cat as cat
inner join fetch cat.mate
left join fetch cat.kittens child
left join fetch child.kittensfetch 구조체는 scroll() 또는 iterate()를 사용하여 호출되는 질의들 내에 사용되지 않음을 노트하라. 또한 fetch은 setMaxResults() 또는 setFirstResult()과 함께 사용되지 않을 것이다. (위의 예제에서 처럼) 한 개의 질의 내에 하나 이상의 콜렉션을 조인 페칭시켜서 한 개의 카티젼 곱을 생성시키는 것이 가능하며, 이 곱의 결과가 당신이 예상하는 것보다 더 크지 않을 것임을 주의하라. 여러 개의 콜렉션 role들을 조인 페칭시키는 것은 또한 때때로 bag 매핑들에 대해 예기치 않은 결과들을 초래하므로, 당신이 이 경우에 당신의 질의들을 처방하는 방법을 주의하라.
TODO: 마지막 문장은 쓸모없고 일반적인 개발자 생각이며, 퇴고하길 바란다. 단어 "때로는(sometimes)"는 어떤 기술 문서 내에 결코 나타나지 말아야 한다.
만일 당신이 (바이트코드 수단으로) 프로퍼티 레벨의 lazy 페칭을 사용할 경우에, Hibernate로 하여금 (fetch all properties를 사용하여)(첫 번째 질의 내에)lazy 프로퍼티들을 즉시 페치시키는 것을 강제시키는 것이 가능하다. 이것은 Hibernate에 특징적인 옵션이다:
select doc from Document doc fetch all properties order by doc.name
select doc from Document doc fetch all properties where lower(doc.name) like '%cats%'
select 절은 어느 객체들과 프로퍼티들이 질의 결과 셋 내에 반환될 것인지를 골라낸다. 다음을 검토하자:
select mate
from Cat as cat
inner join cat.mate as mate질의는 다른 Cat들 중에서 mate들을 select할 것이다. 실제로 당신은 다음과 같이 보다 축약적으로 이 질의를 표현할 수도 있다:
select cat.mate from Cat cat
질의들은 컴포넌트 타입인 프로퍼티들을 포함하는 임의의 값 타입의 프로퍼티들을 반환할 수 있다:
select cat.name from DomesticCat cat where cat.name like 'fri%'
select cust.name.firstName from Customer as cust
질의들은 여러 개의 객체들 과/또는 프로퍼티들을
Object[] 타입의 하나의 배열로서,
select mother, offspr, mate.name
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr또는 하나의 List로서 (HQL에 특정한 특징),
select new list(mother, offspr, mate.name)
from DomesticCat as mother
inner join mother.mate as mate
left outer join mother.kittens as offspr또는 Family 클래스가 하나의 적절한 생성자를 갖고 있음을 가정하면 하나의 실제 타입안전한 Java 객체로서,
select new Family(mother, mate, offspr)
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr반환할 수 있다
당신은 as를 사용하여 select된 표현식들에 alias들을 할당할 수도 있다:
select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n from Cat cat
이것은 select new map(HQL에 특정한 특징)과 함께 사용될 때 가장 유용하다:
select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n ) from Cat cat
이 질의는 alias들로부터 select된 값들로의 하나의 Map을 반환한다.
HQL 질의들은 심지어 프로퍼티들에 대한 집계 함수들의 결과들을 반환할 수도 있다:
select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat) from Cat cat
지원되는 집계 함수들은 다음이다
avg(...), avg(distinct ...), sum(...), sum(distinct ...), min(...), max(...)
count(*)
count(...), count(distinct ...), count(all...)
당신은 (구성된 dialect에 따라, HQL에 특정한 특징임) select 절 내에 산술 연산자들, concatenation, 그리고 인지된 SQL 함수들을 사용할 수 있다:
select cat.weight + sum(kitten.weight)
from Cat cat
join cat.kittens kitten
group by cat.id, cat.weightselect firstName||' '||initial||' '||upper(lastName) from Person
distinct 키워드와 all 키워드가 사용될 수 있고 SQL에서와 같은 의미를 갖는다.
select distinct cat.name from Cat cat select count(distinct cat.name), count(cat) from Cat cat
다음과 같은 질의:
select cat from Cat as cat
은 Cat의 인스턴스들 뿐만 아니라 DomesticCat과 같은 서브클래스들의 인스턴스들을 반환한다. Hibernate 질의들은 from 절 내에서 임의의 자바 클래스 또는 인스턴스를 명명할 수 있다(이식 가능한 EJB-QL 질의들은 오직 매핑된 엔티티들 만을 명명해야 한다). 질의는 그 클래스를 확장하거나 그 인터페이스를 구현하는 모든 영속 클래스들의 인스턴스들을 반환할 것이다. 다음 질의는 모든 영속 객체들을 반환할 것이다:
from java.lang.Object o // HQL only
인터페이스 Named는 여러 영속 클래스들에 의해 구현될 수 있다:
from Named n, Named m where n.name = m.name // HQL only
이들 마지막 두 개의 질의들이 하나 이상의 SQL SELECT를 필요로 할 것임을 노트하라. 이것은 order by 절이 전체 결과 셋을 정확하게 순서(order)지우지 않음을 의미한다. (그것은 또한 당신이 Query.scroll()을 사용하여 이들 질의들을 호출할 수 없음을 의미한다.)
where 절은 반환되는 인스턴스들의 목록을 좁히는 것을 당신에게 허용해준다. 만일 alias가 존재하지 않을 경우, 당신은 이름으로 프로퍼티들을 참조할 수 있다:
select cat from Cat cat where cat.name='Fritz'
는 'Fritz'로 명명된 Cat의 인스턴스들을 반환한다.
select foo from Foo foo, Bar bar where foo.startDate = bar.date
는 Foo의 startDate 프로퍼티와 같은 date 프로퍼티를 가진 bar의 인스턴스가 존재하는 Foo의 모든 인스턴스들을 반환할 것이다. 합성된 경로 표현식들은 where 절을 극히 강력하게 만든다. 다음을 검토하자:
select cat from Cat cat where cat.mate.name is not null
이 질의는 하나의 테이블 (inner) 조인을 가진 하나의 SQL 질의로 변환된다. 만일 당신이 다음과 같은 것을 작성했다면
select foo from Foo foo where foo.bar.baz.customer.address.city is not null
당신은 SQL로된 네 개의 테이블 조인들을 필요로 하는 하나의 질의로 끝낼 것이다.
= 연산자는 프로퍼티들 뿐만 아니라 인스턴스들을 비교하는데 사용될 수 있다:
select cat, rival from Cat cat, Cat rival where cat.mate = rival.mate
select cat, mate from Cat cat, Cat mate where cat.mate = mate
(소문자로 된) 특별한 프로퍼티 id는 객체의 유일 식별자를 참조하는데 사용될 수 있다. (당신은 또한 그것의 매핑된 식별자 프로퍼티 이름을 사용할 수도 있다.). 이 키워드가 HQL에 특정한 것임을 노트하라.
select cat from Cat as cat where cat.id = 123 select cat from Cat as cat where cat.mate.id = 69
두 번짹 질의가 효과적이다. 테이블 조인들이 필요하지 않다!
합성(composite) 식별자들의 프로퍼티들이 또한 사용될 수 있다. Person이 country와 medicareNumber 로 구성된 하나의 합성 식별자를 갖는다고 가정하자.
select person from bank.Person person
where person.id.country = 'AU'
and person.id.medicareNumber = 123456select account from bank.Account account
where account.owner.id.country = 'AU'
and account.owner.id.medicareNumber = 123456다시 한번, 두 번째 질의는 테이블 조인을 필요로 하지 않는다.
마찬가지로 특별한 프로퍼티 class는 다형성 영속의 경우에 하나의 인스턴스의 판별자 값에 접근한다. where 절 내에 삽입된 Java 클래스 이름은 그것의 판별자 값으로 변환될 것이다. 다시 한번, 이것은 HQL에 특정한 것이다.
select cat from Cat cat where cat.class = DomesticCat
당신은 또한 컴포넌트 사용자 타입들 또는 합성(composite) 사용자 타입들(그리고 컴포넌트들을 가진 컴포넌트 타입)인 프로퍼티들을 지정할 수도 있다. (하나의 컴포넌트의 하나의 프로퍼티와는 대조적으로) 컴포넌트 타입인 하나의 프로퍼티로 끝나는 하나의 경로-표현식을 결코 사용하려고 시도하지 말라. 예를 들어, 만일 store.owner이 하나의 컴포넌트 address을 가진 엔티티일 경우에
store.owner.address.city // okay store.owner.address // error!
"any" 타입은 다음 방법으로 하나의 조인을 표현하는 것을 우리에게 허용해주는 특별한 프로퍼티들 id와 class를 갖는다(여기서 AuditLog.item은 <any>로서 매핑된 하나의 프로퍼티이다). Any는 Hibernate에 특징적인 것이다
from AuditLog log, Payment payment where log.item.class = 'Payment' and log.item.id = payment.id
log.item.class와 payment.class는 위의 질의에서 완전히 다른 데이터베이스 컬럼들의 값들을 참조할 것임을 주지하라.
where 절 내에 허용되는 표현식드은 당신이 SQL로 작성할 수 있는 거의 대부분의 종류의 것들을 포함한다:
수학 연산자들 +, -, *, /
바이너리 비교 연산자들 =, >=, <=, <>, !=, like
논리 연산자들 and, or, not
그룹핑을 나타내는 괄호들 ( )
in, not in, between, is null, is not null, is empty, is not empty, member of 그리고 not member of
"간단한" case, case ... when ... then ... else ... end, 그리고 "검색된(searched)" case, case when ... then ... else ... end (HQL에 특징적임)
문자열 연결 ...||... 또는 concat(...,...) (이식가능한 EJB-QL 질의를 위해 concat()을 사용하라)
current_date(), current_time(), current_timestamp()
second(...), minute(...), hour(...), day(...), month(...), year(...), (HQL에 특징적임)
EJB-QL 3.0에 의해 정의된 이므이의 함수 또는 연산자: substring(), trim(), lower(), upper(), length(), locate(), abs(), sqrt(), bit_length()
coalesce() 그리고 nullif()
cast(... as ...), 여기서 두 번째 아규먼트는 하나의 Hibernate 타입의 이름이고, 만일 ANSI cast()과 extract()가 기본 데이터베이스에 의해 지원될 경우에는extract(... from ...)
sign(), trunc(), rtrim(), sin()과 같이 임의의 데이터베이스-지원되는 SQL 스칼라 함수
JDBC IN 파라미터들 ?
명명된 파라미터들 :name, :start_date, :x1
SQL 리터럴들 'foo', 69, '1970-01-01 10:00:01.0'
Java public static final 상수들 eg.Color.TABBY
in 과 between은 다음과 같이 사용될 수도 있다:
select cat from DomesticCat cat where cat.name between 'A' and 'B'
select cat from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )
and the negated forms may be written
select cat from DomesticCat cat where cat.name not between 'A' and 'B'
select cat from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )
마찬가지로, is null과 is not null이 null 값들을 테스트하는데 사용될 수 있다.
Boolean들은 Hibernate 구성에서 HQL 질의 치환을 선언함으로써 표현식들 내에 쉽게 사용될 수 있다:
hibernate.query.substitutions true 1, false 0
이것은 이 HQL로부터 변환된 SQL 내에서 true 및 false 키워드들을 리터럴들 1과 0으로 바꾸게 될 것이다:
select cat from Cat cat where cat.alive = true
당신은 특별한 프로퍼티 size 또는 특별한 size() 함수로서 콜렉션의 사이즈를 테스트할 수 있다(HQL에 특징적임).
select cat from Cat cat where cat.kittens.size > 0
select cat from Cat cat where size(cat.kittens) > 0
인덱싱 된 콜렉션들의 경우, 당신은 minindex 함수와 maxindex 함수를 사용하여 최소 인덱스와 최대 인덱스를 참조할 수 있다. 유사하게 당신은 minelement 함수와 maxelement 함수를 사용하여 기본 타입을 가진 하나의 콜렉션의 최소 요소와 최대 요소를 참조할 수 있다. 이것들은 HQL에 특정한 특징들이다.
select cal from Calendar cal where maxelement(cal.holidays) > current date
select order from Order order where maxindex(order.items) > 100
select order from Order order where minelement(order.items) > 10000
SQL 함수들 any, some, all, exists, in은 하나의 콜렉션의 요소 세트 또는 인덱스 세트 (elements 함수와 indices 함수) 또는 하나의 서브질의의 결과를 전달했을 때 지원된다. 서브질의들이 EJB-QL에 의해 지원되는 반면에, elements와 indices는 특정한 HQL 특징들이다.
select mother from Cat as mother, Cat as kit where kit in elements(foo.kittens)
select p from NameList list, Person p where p.name = some elements(list.names)
select cat from Cat cat where exists elements(cat.kittens)
select cat from Player p where 3 > all elements(p.scores)
select cat from Show show where 'fizard' in indices(show.acts)
이들 구조체들 - size, elements, indices, minindex, maxindex, minelement, maxelement - 은 오직 Hibernate3에서 where 절 내에서만 사용될 수 있음을 노트하라.
HQL에서, 인덱싱 된 콜렉션들(배열들, 리스트들, map들)의 요소들은 (오직 where 절 내에서만) index에 의해 참조될 수 있다:
select order from Order order where order.items[0].id = 1234
select person from Person person, Calendar calendar
where calendar.holidays['national day'] = person.birthDay
and person.nationality.calendar = calendarselect item from Item item, Order order where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11
select item from Item item, Order order where order.items[ maxindex(order.items) ] = item and order.id = 11
[] 내의 표현식은 심지어 산술 표현식일 수 있다.
select item from Item item, Order order where order.items[ size(order.items) - 1 ] = item
HQL은 또한 하나의 one-to-many 연관의 요소들 또는 값들을 가진 콜렉션의 요소들에 대해 미리 빌드된 index() 함수를 제공한다.
select item, index(item) from Order order
join order.items item
where index(item) < 5기본 데이터베이스에 의해 지원되는 스칼라 SQL 함수들이 사용될 수 있다
select cat from DomesticCat cat where upper(cat.name) like 'FRI%'
만일 당신이 아직 이 모든 것이 확신되지 않을 경우, 다음 질의가 SQL에서 얼마나 더 가독적이 있는지 덜 가독적인지를 생각하라:
select cust
from Product prod,
Store store
inner join store.customers cust
where prod.name = 'widget'
and store.location.name in ( 'Melbourne', 'Sydney' )
and prod = all elements(cust.currentOrder.lineItems)힌트: 다음과 같은 것
SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
FROM customers cust,
stores store,
locations loc,
store_customers sc,
product prod
WHERE prod.name = 'widget'
AND store.loc_id = loc.id
AND loc.name IN ( 'Melbourne', 'Sydney' )
AND sc.store_id = store.id
AND sc.cust_id = cust.id
AND prod.id = ALL(
SELECT item.prod_id
FROM line_items item, orders o
WHERE item.order_id = o.id
AND cust.current_order = o.id
)하나의 질의에 의해 반환되는 리스트는 반환된 클래스 또는 컴포넌트들의 임의의 프로퍼티에 의해 순서지워질 수 있다:
select cat from DomesticCat cat order by cat.name asc, cat.weight desc, cat.birthdate
선택적인 asc 또는 desc는 각각 오름차순 또는 내림차순을 나타낸다.
집계 값들을 반환하는 하나의 질의는 반환된 클래스 또는 컴포넌트들의 임의의 프로퍼티에 의해 그룹지워질 수 있다:
select cat.color, sum(cat.weight), count(cat) from Cat cat group by cat.color
select foo.id, avg(name), max(name) from Foo foo join foo.names name group by foo.id
하나의 having 절이 또한 허용된다.
select cat.color, sum(cat.weight), count(cat) from Cat cat group by cat.color having cat.color in (eg.Color.TABBY, eg.Color.BLACK)
SQL 함수들과 집계 함수들이 기본 데디터베이스에 의해 지원될 경우에 , having 절과 order by 절 속에 허용된다. (예를 들어 MySQL에서는 지원되지 않음).
select cat
from Cat cat
join cat.kittens kitten
group by cat
having avg(kitten.weight) > 100
order by count(kitten) asc, sum(kitten.weight) descgroup by 절이든 order by 절이든 어느 것도 산술 표현식들을 포함할 수 없음을 노트하라.
subselect들을 지원하는 데이터베이스들에 대해, EJB-QL은 질의들 내에 서브질의들을 지원한다. 하나의 서브질의는 (흔히 SQL 집계함수 호출에 의해) 괄호들에 의해 둘러싸워져야 한다. 심지어 서로 관련된 서브질의들(outer 질의 내에서 하나의 alias를 참조하는 서브질의들)이 허용된다.
select fatcat from Cat as fatcat
where fatcat.weight > (
select avg(cat.weight) from DomesticCat cat
)select cat from DomesticCat as cat
where cat.name = some (
select name.nickName from Name as name
)select cat from Cat as cat
where not exists (
from Cat as mate where mate.mate = cat
)select cat from DomesticCat as cat
where cat.name not in (
select name.nickName from Name as name
)select list 내에 하나 이상의 표현식을 가진 서브질의들의 경우에, 당신은 하나의 튜플(tuple) 생성자를 사용할 수 있다:
select cat from Cat as cat
where not ( cat.name, cat.color ) in (
select cat.name, cat.color from DomesticCat cat
)(Oracle이나 HSQLDB가 아닌) 몇몇 데이터베이스들 상에서, 당신은 예를 들어 컴포넌트들이나 합성(composite) 사용자 타입들을 질의할 때 다른 컨텍스트들 내에서 튜플(tuple) 생성자들을 사용할 수 있음을 노트하라:
select cat from Person where name = ('Gavin', 'A', 'King')Which is equivalent to the more verbose:
select cat from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')
당신이 이런 종류의 것을 행하고자 원하자 않는 두 가지 좋은 이유들이 존재한다: 첫 번째로, 그것은 데이터베이스 플랫폼들 사이에서 완전하게 이식가능하지 않다; 두 번째로 그 질의는 이제 매핑 문서 내에 있는 프로퍼티들의 순서에 종속된다.
Hibernate 질의들은 괘 강력하고 복잡해질 수 있다. 사실, 질의 언어의 힘은 Hibernate(그리고 이제 EJB-QL)의 주요 판매 포인트들 중 하나이다. 다음은 내가 최근의 프로젝트에서 사용했던 질의들과 매우 유사한 몇몇 예제 질의들이다. 당신이 작성하게 될 대부분의 질의들은 이것들과 훨씬 유사함을 노트하라!
다음 질의는 합계값에 따라 결과들을 순서지우는, 주문 id, 아이템들의 개수, 그리고 특정 고객에 대해 모든 지불되지 않은 주문들에 대한 합계 값, 그리고 주어진 최소 합계를 반환한다. 가격 결정에 있어, 그것은 현재의 카다록을 사용한다. ORDER, ORDER_LINE, PRODUCT, CATALOG 그리고 PRICE 테이블들에 대해 귀결되는 SQL 질의는 네 개의 inner join들과 한 개의 (상관되지 않은) subselect를 갖는다.
select order.id, sum(price.amount), count(item)
from Order as order
join order.lineItems as item
join item.product as product,
Catalog as catalog
join catalog.prices as price
where order.paid = false
and order.customer = :customer
and price.product = product
and catalog.effectiveDate < sysdate
and catalog.effectiveDate >= all (
select cat.effectiveDate
from Catalog as cat
where cat.effectiveDate < sysdate
)
group by order
having sum(price.amount) > :minAmount
order by sum(price.amount) desc괴물 같은 것! 실제로 실 세계에서, 나는 서브질의들을 매우 좋아하지 않아서, 나의 질의는 실제로 다음과 같았다:
select order.id, sum(price.amount), count(item)
from Order as order
join order.lineItems as item
join item.product as product,
Catalog as catalog
join catalog.prices as price
where order.paid = false
and order.customer = :customer
and price.product = product
and catalog = :currentCatalog
group by order
having sum(price.amount) > :minAmount
order by sum(price.amount) desc다음 질의는 가장 최근의 상태 변경이 현재 사용자에 의해 행해졌던 AWAITING_APPROVAL 상태에 있지 않는 모든 지불들을 제외한, 각각의 상태에 있는 지불들의 개수를 카운트한다. 그것은 PAYMENT, PAYMENT_STATUS 그리고 PAYMENT_STATUS_CHANGE 테이블들에 대해 두 개의 inner 조인들과 한 개의 상관된 subselect를 가진 하나의 SQL로 변환된다.
select count(payment), status.name
from Payment as payment
join payment.currentStatus as status
join payment.statusChanges as statusChange
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
or (
statusChange.timeStamp = (
select max(change.timeStamp)
from PaymentStatusChange change
where change.payment = payment
)
and statusChange.user <> :currentUser
)
group by status.name, status.sortOrder
order by status.sortOrder만일 내가 statusChanges 콜렉션을 하나의 set이 아닌, 하나의 리스트로서 매핑했다면, 그 질의는 작성하기가 훨씬 더 간단했을 것이다.
select count(payment), status.name
from Payment as payment
join payment.currentStatus as status
where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
group by status.name, status.sortOrder
order by status.sortOrder하지만 그 질의는 HQL 특징적인 것이었다.
다음 질의는 현재 사용자가 속해 있는 조직에 대한 모든 계정들과 지불되지 않은 지불들을 반환하는데 MS SQL Server isNull() 함수를 사용한다. 그것은 ACCOUNT, PAYMENT, PAYMENT_STATUS, ACCOUNT_TYPE, ORGANIZATION 그리고 ORG_USER 테이블들에 대해 세 개의 inner 조인과, 한 개의 oute 조인과 한 개의 subselect를 가진 한 개의 SQL로 변환된다.
select account, payment
from Account as account
join account.holder.users as user
left outer join account.payments as payment
where :currentUser = user
and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
order by account.type.sortOrder, account.accountNumber, payment.dueDateHibernate는 이제 HQL/EJB-QL 내에 UPDATE 문장과 DELETE 문장을 지원한다. 상세한 것은 6.1절. “대용량 update/delete”를 보라.
하나의 콜렉션의 사이즈에 따라 결과를 순서지우는데 다음 질의를 사용하라:
select usr.id, usr.name
from User as usr
left join usr.messages as msg
group by usr.id, usr.name
order by count(msg)만일 당신의 데이터베이스가 subselect들을 지원할 경우, 당신은 당신의 질의의 where 절 속에 select 사이즈에 따른 조건을 위치지울 수 있다:
from User usr where size(usr.messages) >= 1
만일 당신의 데이터베이스가 subselect들을 지원하지 않을 경우, 다음 질의를 사용하라:
select usr.id, usr.name
from User usr.name
join usr.messages msg
group by usr.id, usr.name
having count(msg) >= 1이 해결책이 inner 조인 때문에 0개의 메시지들을 가진 한 개의 User를 반환할 수 없으므로, 다음 형식이 또한 유용하다:
select usr.id, usr.name
from User as usr
left join usr.messages as msg
group by usr.id, usr.name
having count(msg) = 0