JOIN
Inner Join 메서드
- innerJoin()은 두개의 파라미터를 받음
- 조인할 대상 엔터티의 경로
from에서 갖고 있는 FK
- 조인 조건에 사용될 엔터티 (on절에 들어가야 하는 내용)
조인할 테이블
@Test
@DisplayName("내부 조인 예제")
void innerJoinTest() {
List<Tuple> idolList = factory
.select(idol, group)
.from(idol)
.innerJoin(idol.group, group)
.fetch();
}
@Test
@DisplayName("2022년에 발매된 앨범이 있는 아이돌의 이름과 그룹명과 앨범명과 발매년도 조회")
void selectAlbumReleasedYear() {
int year = 2022;
List<Tuple> list = factory
.select(idol.idolName, group.groupName, album.albumName, album.releaseYear)
.from(idol)
.innerJoin(idol.group, group)
.innerJoin(group.albums, album)
.where(album.releaseYear.in(year))
.fetch();
for (Tuple tuple : list) {
String name = tuple.get(idol.idolName);
String gName = tuple.get(group.groupName);
String aName = tuple.get(album.albumName);
int releaseYear = tuple.get(album.releaseYear);
System.out.println("Idol: " + name + ", Group: " + gName + ", Album: " + aName + ", ReleaseYear: " + releaseYear);
}
}
Outer Join 메서드
@Test
@DisplayName("Left Outer Join")
void outerJoinTest() {
List<Tuple> result = factory
.select(idol, group)
.from(idol)
.leftJoin(idol.group, group)
.fetch();
assertFalse(result.isEmpty());
for (Tuple tuple : result) {
Idol i = tuple.get(idol);
Group g = tuple.get(group);
System.out.println("\nIdol: " + i.getIdolName()
+ ", Group: "
+ (g != null ? g.getGroupName() : "솔로가수"));
}
}
nvl을 꼭 사용해야 할때
- QueryDsl에서는 nvl, rollup, cube, 윈도우함수 등을 지원하지 않아
결국에는 native query를 써야한다.
- IdolRepositoryImpl
public class IdolRepositoryImpl implements IdolCustomRepository {
private final JdbcTemplate template;
private final EntityManager em;
private final JPAQueryFactory factory;
public void nativeQuery123() {
String sql = "SELECT " +
"I.idol_id, NVL(G.group_id, '솔로가수') AS g_id" +
"FROM tbl_idol I" +
"LEFT JOIN tbl_group G" +
"ON I.group_id = G.group_id";
}
서브쿼리
- subQuery는 'JPAExpressions' 객체를 사용
- JPAExpressions.select()해서 넣으면 됨.
@Test
@DisplayName("특정 그룹의 평균 나이보다 많은 아이돌 조회")
void subQueryTest1() {
List<Idol> result = factory
.select(idol)
.from(idol)
.where(idol.age.gt(
JPAExpressions
.select(idol.age.avg())
.from(idol)
.innerJoin(idol.group, group)
.where(group.groupName.eq("르세라핌"))
).and(idol.group.isNotNull())
)
.fetch();
- 연관 서브쿼리에서 하나의 테이블에 다른 별칭을 사용해야 할 경우.
new Qtype으로 생성해서 해결
@Test
@DisplayName("그룹별 가장 최근에 발매된 앨범을 조회")
void subQueryTest2() {
QAlbum albumA = new QAlbum("albumA");
QAlbum albumS = new QAlbum("albumS");
List<Tuple> list = factory
.select(group.groupName, albumA.albumName, albumA.releaseYear)
.from(group)
.innerJoin(group.albums, albumA)
.where(albumA.id.in(
JPAExpressions
.select(albumS.id)
.from(albumS)
.where(albumS.group.id.eq(albumA.group.id)
.and(albumS.releaseYear.eq(
JPAExpressions
.select(albumS.releaseYear.max())
.from(albumS)
.where(albumS.group.id.eq(albumA.group.id))
))
)
))
.distinct()
.fetch();
}