SQL작성
오라클의 검색 조건에 대한 처리는 인라인 뷰 내부에서 이루어진다.
기존의 list출력 쿼리에서 검색한 내용만을 출력하게끔 쿼리를 변경해보면 아래처럼 작성할 수 있을 것이다.
(아래의 쿼리는 페이징처리가 포함된 쿼리이다.)
select *
from (
select /*+ INDEX_DESC(tbl_board tbl_board_pk) */ rownum rn, bno, title, content, writer, regdate, updatedate
from tbl_board
where title like '%테스트%' or content like '%테스트%'
and rownum <= 20
)where rn > 10;
그러나 결과를 출력해보면 10개의 데이터가 아닌 더 많은 데이터를 출력함을 알 수 있다.
왜냐하면 AND연산이 OR연산보다 더 우선이기 때문에 실제로 쿼리는 아래와 같은 결과처럼 작동한다.
where title like '%테스트%' or
(content like '%테스트%' and rownum <= 20)
그렇다면 우리가 하려는 작업은,
(1) title like '%테스트%' 조건을 먼저 처리해서 결과를 출력하고 (2) content like '%테스트%' 조건을 처리해서 출력한 것을 OR연산을 통해 반환해주고 싶은 것이다. 그러면 간단히 괄호만 씌워주면 된다.
select *
from (
select /*+ INDEX_DESC(tbl_board tbl_board_pk) */ rownum rn, bno, title, content, writer, regdate, updatedate
from tbl_board
where (title like '%테스트%' or content like '%테스트%')
and rownum <= 20
)where rn > 10;
간단~🤷♀️
AND와 OR가 섞여있는 SQL을 작성하는 경우 우선 순위 연산자인 '( )'를 이용해서 OR조건을 처리해야함을 기억하자.
그러면 쿼리에서 페이징을 위한 정보 말고도 검색을 위한 정보까지 전달해주어야 함을 알았다.
지금 코드는 Criteria클래스에서 pageNum과 amount만 멤버로 가지고 있지만 검색대상(검색조건)과 검색키워드를 추가적으로 전달하기 위해 멤버변수 type과 keyword를 추가해준다.
@Getter
@Setter
@ToString
public class Criteria {
private int pageNum; //페이징
private int amount; //페이징
private String type; //검색
private String keyword; //검색
public Criteria(){ //페이징
this(1,10);
}
public Criteria(int pageNum, int amount) { //페이징
this.pageNum = pageNum;
this.amount = amount;
}
}
검색은 단일 조건의 경우만 가능하게 처리할 것이다.
MyBatis의 동적 SQL
SQL문에서 검색 조건이 변하면 SQL의 내용 역시 변하기 때문에 XML이나 어노테이션과 같이 고정된 문자열을 작성하는 방식으로는 제대로 처리할 수 없다. 이 때 MyBatis의 동적 태그 기능을 사용할 수 있다.
MyBatis의 동적 태그는 SQL을 파라미터들의 조건에 맞게 조정이 가능하게 하고,
약간의 구문을 이용해서 전달되는 파라미터를 가공해서 경우에 따라 다른 SQL을 만들어 주는 기능이 있다.
아래에 따로 동적SQL에 대한 내용을 포스팅하였으니 해당 내용을 공부한 뒤 실습을 진행하도록 한다.
2021.08.08 - [Spring/개념지식 및 에러사항] - [MyBatis] 동적 SQL
mybatis 동적태그를 이용한 getListWithPaging()
👇 기존의 mapper.xml의 getListWithPaing() 확인하기
<select id="getListWithPaging" resultType="com.taeong.domain.BoardVO">
<![CDATA[
select *
from (
select /*+ INDEX_DESC(tbl_board tbl_board_pk) */
rownum rn, bno, title, content, writer, regdate, updatedate
from tbl_board
where rownum <= #{pageNum} * #{amount}
)
where rn > (#{pageNum} - 1) * #{amount}
]]>
mybatis 동적태그를 반영한 getListWithPaging()
아직 완성 코드 아님
<select id="getListWithPaging" resultType="com.taeong.domain.BoardVO">
<![CDATA[
select *
from (
select /*+ INDEX_DESC(tbl_board tbl_board_pk) */
rownum rn, bno, title, content, writer, regdate, updatedate
from tbl_board
where
]]>
<trim prefix="(" suffix=") AND " prefixOverrides="OR">
<choose>
<when test="type == 'T'.toString()">
title like '%'||#{keyword}||'%'
</when>
<when test="type == 'C'.toString()">
content like '%'||#{keyword}||'%'
</when>
<when test="type == 'W'.toString()">
writer like '%'||#{keyword}||'%'
</when>
</choose>
</trim>
<![CDATA[
rownum <= #{pageNum} * #{amount}
)
where rn > (#{pageNum} - 1) * #{amount}
]]>
type분류
◾ T = title
◾ C = content
◾ W= writer
MyBatis는 <sql>이라는 태그를 이용해서 SQL의 일부를 별도로 보관하고, include해줌으로써 사용이 가능하다.
아까 동적태그를 반영한 코드 부분을 따로 떼내어서 별도의 <sql>구문을 만들어주면 여러 쿼리에서 해당 sql과 같은 알고리즘으로 동작하는 경우 include해주어 코드 중복을 피할 수 있다.
👇 <sql>태그를 이용해서 sql을 별도로 보관
<!-- <sql>코드는 <include>로 사용할 수 있음 -->
<sql id="criteria">
<trim prefix="(" suffix=") AND " prefixOverrides="OR">
<choose>
<when test="type == 'T'.toString()">
title like '%'||#{keyword}||'%'
</when>
<when test="type == 'C'.toString()">
content like '%'||#{keyword}||'%'
</when>
<when test="type == 'W'.toString()">
writer like '%'||#{keyword}||'%'
</when>
</choose>
</trim>
</sql>
위의 <sql>구문을 쿼리문 중간에 include하는 경우 <include refid="id명"></include>으로 처리할 수 있다.
<select id="getListWithPaging" resultType="com.taeong.domain.BoardVO">
<![CDATA[
select *
from (
select /*+ INDEX_DESC(tbl_board tbl_board_pk) */
rownum rn, bno, title, content, writer, regdate, updatedate
from tbl_board
where
]]>
<include refid="criteria"></include>
<![CDATA[
rownum <= #{pageNum} * #{amount}
)
where rn > (#{pageNum} - 1) * #{amount}
]]>
</select>
출력 데이터의 개수를 반환하는 getTotalCount()도 검색결과를 고려해서 카운트해야하기 때문에 같은 알고리즘을 사용하게 된다. 간단히 <include>를 사용하여 sql쿼리를 추가시켜줄 수 있다.
<select id="getTotalCount" resultType="int">
<![CDATA[
select count(*) from tbl_board where
]]>
<include refid="criteria"></include>
<![CDATA[
bno > 0
]]>
</select>
getTotalCount에서 #{변수}사용이 가능하게 하기 위해서는 파라미터로 그 값을 넘겨줘야 하기 때문에 Mapper.java, Service.java, ServiceImpl.java, Controller.java의 메소드의 파라미터에 모두 Criteria객체를 넣어준다.
👇 이런식으로 하라는 얘기임 (전체 파라미터 수정은 따로 코드를 첨부하지 x)
public int getTotalCount(Criteria cri);
다음 포스팅에서는 화면에서 검색기능을 처리하는 경우에 대해서 다루도록 하겠다. 🙋♀️
'Spring > 게시판프로젝트' 카테고리의 다른 글
[Spring] 게시판 프로젝트17 - 검색기능2 (화면 처리) (0) | 2021.08.10 |
---|---|
[Spring] 게시판 프로젝트15 - 페이징 처리3 (0) | 2021.08.07 |
[Spring] 게시판 프로젝트14 - 페이징 처리2 (0) | 2021.07.20 |
[Spring] 게시판 프로젝트13 - 페이징 처리1 (0) | 2021.07.20 |
[Spring] 게시판 프로젝트12 - 게시물 수정, 삭제 (0) | 2021.07.14 |
댓글