SELECT m FROM Member m // 회원
SELECT m.team FROM Member m // 팀
위의 쿼리문을 보면 둘 다 엔티티를 프로젝션 대상으로 사용했다.
이렇게 조회한 엔티티는 영속성 컨텍스트에서 관리된다.
String query = "SELECT a FROM Address a";
위의 쿼리는 잘못된 쿼리이다. 왜냐하면 임베디드 타입인 Address를 조회의 시작점으로 사용했기 때문이다.
위의 쿼리를 올바르게 고치면 아래와 같은 쿼리로 변경하게 된다.
String query = "SELECT o.address FROM Order o";
List<Address> address = em.createQuery(query, Address.class)
.getResultList();
전체 회원의 이름을 조회하려면 아래와 같이 쿼리하면 될 것이다.
// 전체 회원의 이름을 조회하는 예제
List<String> usernames =
em.createQuery("SELECT username FROM Member m", String.class)
.getResultList();
중복 데이터를 제거하려면 SELECT절 바로 뒤에 DISTINCT를 사용하면 된다.
통계 쿼리도 주로 스칼라 타입으로 조회한다.
// 스칼라 타입을 사용한 통계쿼리 예제
Double orderAmountAvg =
em.createQuery("SELECT AVG(o.orderAmount) FROM Order o", Double.class)
.getSingleResult();
// 여러 프로젝션 예제
Query query =
em.createQuery("SELECT m.username, m.age FROM Member m");
List resultList = query.getResultList();
Iterator iterator = resultList.iterator();
while(iterator.hasNext()) {
Object[] row = (Object[]) iterator.next();
String username = (String) row[0];
Integer age = (Integer) row[1];
}
// 여러 프로젝션 엔티티 타입 조회 예제
// 제네릭에 Object[]를 사용하면 조금 더 간결하게 개발할 수 있다.
List<Object[]> resultList =
em.createQuery("SELECT o.member, o.product, o.orderAmount FROM Order o")
.getResultList();
for(Object[] row : resultList) {
Member member = (Member) row[0]; // 엔티티
Product product = (Product) row[1]; // 엔티티
int orderAmount = (Integer) row[2]; // 스칼라
}
💡 이렇게 조회한 엔티티는 영속성 컨텍스트에서 관리된다.
// NEW 명령어 사용 예제
TypedQuery<UserDTO> query =
em.createQuery("SELECT new jpabook.jpql.UserDTO(m.username, m.age)
FROM Member m", UserDTO.class);
List<UserDTO> resultList = query.getResultList();
NEW 명령어를 사용할 때는 아래 2가지 사항에 유의해야 한다.
JPA는 페이징을 아래의 두 API로 추상화 했다.
// 페이징 API 사용 예제
List<Member> resultList =
em.createQuery("SELECT m FROM Member m ORDER BY m.username DESC")
.setFirstResult(10)
.setMaxResult(20)
.getResultList();
💡 페이징 SQL을 더 최적화 하고 싶다면 JPA가 제공하는 페이징 API가 아닌 네이티브 SQL을 사용해야 한다.
// 순서대로 회원수, 나이 합, 평균 나이, 최대 나이, 최소 나이를 구하는 SQL
SELECT
COUNT(m), // 회원 수
SUM(m.age), // 나이 합
AVG(m.age), // 평균 나이
MAX(m.age), // 최대 나이
MIN(m.age) // 최소 나이
FROM Member m
집합 함수의 종류와 그 리턴값을 정리한 내용은 아래와 같다
💡 SUM은 BigInteger를 합하면 BigInteger, BigDecimal을 합하면 BigDecimal을 반환한다.