본문 바로가기

웹 프로그래밍/JPA

Querydls 기본


use_sql_comments: true

추가시 Querydls이 어떻게 JPQL로 바뀌는지 주석으로 확인 가능


검색 조건 쿼리

member.username.eq("member1") // username = 'member1'

member.username.ne("member1") // username != 'member1'

 

member.username.isNotNull() // 이름이 is not null

 

member.age.in(10, 20) // age in (10, 20)

member.age.notIn(10, 20) // age not in (10, 20)

member.age.between(10, 30) // between 10, 30

 

member.age.goe(30) // age >= 30(greater or equal)

member.age.gt(30) // age > 30(greater than)

member.age.loe(30) // age <= 30

member.age.lt(30) // age < 30

 

member.username.like("member%") // like 검색

member.username.contains("member") // like '%member%' 검색

member.username.startWith("member") // like 'member%' 검색

 

 

@Test
public void searchAndParam(){
    Member findMember = queryFactory
            .selectFrom(member)
            .where(
                    member.username.eq("member1"),
                    member.age.eq(10)
            )
            .fetchOne();

    assertThat(findMember.getUsername()).isEqualTo("member1");

}

and Param는 ,(콤마)를 사용해서 생략가능 -> 동적쿼리시 위력발휘


결과 조회

fetch(): 리스트 조회, 데이터 없으면 빈 리스트

fetchOne(): 단건 조회, 없으면 null 둘이상이면 Exception

fetchFrist(): limit(1).fetchOne()

fetchResults(): 페이징 정보 포함, total count 쿼리 추가 실행 (참고: 복잡한 쿼리를 최적화 할때는 비권장) 

QueryResults<Member> results = queryFactory
        .selectFrom(member)
        .fetchResults();

results.getTotal();
List<Member> content = results.getResults();

fetchCount(): count 쿼리로 변경해서 count 수 조회

 

 

select count(m) from Member m -> JPQL에 엔티티를 직접 지정하면 아이디 즉 count(m.id)로 바뀜


정렬

List<Member> result = queryFactory
        .selectFrom(member)
        .where(member.age.eq(100))
        .orderBy(member.age.desc(), member.username.asc().nullsLast())
        .fetch();

1. 나이 내림차순 2. 이름 오름차순  3. 이름없으면 맨뒤로


페이징

List<Member> result = queryFactory
        .selectFrom(member)
        .orderBy(member.username.desc())
        .offset(1)
        .limit(2)
        .fetch();

집합

List<Tuple> result = queryFactory
        .select(
                member.count(),
                member.age.sum(),
                member.age.avg(),
                member.age.max(),
                member.age.min()
        )
        .from(member)
        .fetch();

튜플을 쓰는이유: 지금은 셀렉트 데이터 타입이 여러개이기 때문임

 

그룹핑

List<Tuple> result = queryFactory
        .select(team.name, member.age.avg())
        .from(member)
        .join(member.team, team)
        .groupBy(team.name)
        .fetch();

 

having: 걸러

.groupBy(item.price)
.having(item.price.gt(1000))

조인

List<Member> result = queryFactory
        .selectFrom(member)
        .join(member.team, team)
        .where(team.name.eq("teamA"))
        .fetch();

테이블간 연관관계가 있어야만 조인되는것은 아니다. 

 

세타조인: 무지성 막조인(연관관계 없는 필드 끼리도 가능)

List<Member> result = queryFactory
        .select(member)
        .from(member, team)
        .where(member.username.eq(team.name))
        .fetch();

테이블이 곱하기 됨


페치 조인(쿼리 한방에 데이터 몽땅 가져오기): 주로 N+1 문제 해결

Member findMember = queryFactory
        .selectFrom(member)
        .join(member.team, team).fetchJoin()
        .where(member.username.eq("member1"))
        .fetchOne();

fetchJoin()만 추가


조인 ON 절

 

1. 필터링 용도

List<Tuple> result = queryFactory
        .select(member, team)
        .from(member)
        .leftJoin(member.team, team)
        .on(team.name.eq("teamA"))
        .fetch();

멤버는 다 조회하면서 팀 이름이 teamA인것만 가져오고 나머지는 null

-> where는 팀 이름이 teamA인 멤버만 가져옴 (inner join일 경우는 on절과 where절이 똑같음)

 

2. 연관관계 없는 필드 조인

 

List<Tuple> result = queryFactory
        .select(member, team)
        .from(member)
        .leftJoin(team).on(member.username.eq(team.name))
        .fetch();

(주의) 위에 leftJoin(member.team, team) 과 달리 leftJoin(team)에 on절 사용

세타조인과 달리 on절을 사용해서 멤버테이블을 살리면서 left join가능


서브 쿼리: 쿼리 안에 쿼리

where절에 서브쿼리

 

QMember memberSub = new QMember("memberSub"); // 충돌 일어나지 않게 서브쿼리 별칭 구분해줘야함

        List<Member> result = queryFactory
                .selectFrom(member)
                .where(member.age.eq(
                        JPAExpressions
                                .select(memberSub.age.max())
                                .from(memberSub)
                ))
                .fetch();

 

 

        List<Member> result = queryFactory
                .selectFrom(member)
                .where(member.age.in(
                        JPAExpressions
                                .select(memberSub.age)
                                .from(memberSub)
                                .where(memberSub.age.gt(10))
                ))
                .fetch();

 

select절에 서브쿼리

 

QMember memberSub = new QMember("memberSub");

        List<Tuple> result = queryFactory
                .select(member.username,
                        JPAExpressions
                                .select(memberSub.age.avg())
                                .from(memberSub))
                .from(member)
                .fetch();

 

한계: from절에선 서브쿼리 못씀

 

해결방법

1.서브쿼리를 join으로 변경

2.애플리케이션에서 쿼리 두번 나눠서 실행

3.nativeSQL 사용


Case 문

 

List<String> result = queryFactory
                .select(member.age
                        .when(10).then("열살")
                        .when(20).then("스무살")
                        .otherwise("기타"))
                .from(member)
                .fetch();

 

복잡할때: CaseBuilder 사용

 

        List<String> result = queryFactory
                .select(new CaseBuilder()
                        .when(member.age.between(0, 20)).then("0~20살")
                        .when(member.age.between(21, 30)).then("21~30살")
                        .otherwise("기타"))
                .from(member)
                .fetch();

 

왠만해서는 디비는 최소한의 필터링과 그룹핑만 하도록 해야함 -> 애플리케이션에서 처리하도록 함

 


상수,문자 더하기

List<Tuple> result = queryFactory
                .select(member.username, Expressions.constant("A")) // 그냥 문자 A 이름옆에 추가
                .from(member)
                .fetch();

 

문자 붙이기

 

 //username_age
        List<String> result = queryFactory
                .select(member.username.concat("_").concat(member.age.stringValue())) // int -> String 형변환 주의
                .from(member)
                .where(member.username.eq("member1"))
                .fetch();


 

'웹 프로그래밍 > JPA' 카테고리의 다른 글

연관관계 편의 메서드  (0) 2024.01.15
Querydsl 중급  (0) 2023.03.22
스프링 데이터 JPA  (0) 2023.03.18
JPA 활용(2) 팁 정리  (0) 2023.03.16
JPA 활용(1) 팁 정리  (0) 2023.03.08