문제
마이페이지 피드에서 게시글 목록을 출력한다. 유저가 팔로우하는 태그를 사용한 게시글이거나, 팔로우하는 유저가 작성한 게시글이여야 한다. 게시글은 최신순으로 출력하고, 중복되어서는 안 된다.
해결방법
SQL에서 피드 목록을 출력할 때의 조건
피드를 출력하기 위해서는 유저가 팔로우하는 태그를 사용하는 게시글 목록을 우선 select 하고, 유저가 팔로우하는 유저가 작성한 게시글 목록을 select해야 한다. 이때 함께 select하되 게시글은 중복되어서는 안 된다.
시도했지만 실패한 방법
User가 팔로우하는 유저 목록과 태그 목록을 파라미터로 넘겨 이를 forEach로 반복해 where 조건을 걸려고 하였다. 이 경우
ArticleController
에서FollowService
를 사용하여 유저 목록과 태그 목록을 가져오고, 이를ArticleService.listFeed()
의 파라미터로 넘겨주기 때문에 비효율적이다. 뿐만 아니라 DB에는 user의 일련번호 컬럼이 관계테이블인usr_tag
,follow
뿐만 아니라article
테이블에도 들어 있기 때문에 이 일련번호만 있으면 쿼리를 할 수 있다.또한 한 쿼리문으로 usr_tag, follow 테이블을 조인하고, where 조건을 or를 줘서 게시글 목록을 select하려고 하였다. 이 경우 같은 게시글이 중복되어 select되는 문제가 있었다. SQL문을 두 개로 분리하고, 이를 합칠 필요를 느꼈다.
Union
이때 사용하는 sql 문법이 Union이다. Union은 여러 개의 SQL문을 합쳐 하나의 SQL문으로 만들어주는 방법이다. 두 개의 쿼리의 합집합을 만들어준다고 생각하면 쉽다.
Union과 UnionAll은 두 쿼리문을 하나로 합쳐준다는 것에 공통점이 있다. 그러나 Union은 두 쿼리 결과의 중복값을 제거해서 보여주고, UnionAll은 중복된 값도 전부 다 보여준다는 차이점이 있다. Union은 중복값 제거를 위해 연산을 한 번 더 해야 하기 때문에 UnionAll이 Union보다 빠르다.
Union을 사용할 때는 컬럼명과 컬럼별 데이터타입이 같아야 한다. 컬럼명이 같지 않을 경우 as
를 사용해 컬럼명을 같게 만들어줘야 한다.
완성된 SQL문
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
select
feed.arno,
feed.title,
feed.content,
feed.cdt,
feed.cano,
feed.vw_cnt,
feed.uno,
feed.article_nick,
feed.article_photo,
feed.tno,
feed.tag_name,
feed.tag_color,
feed.font_color
from (
select
a.arno,
a.title,
a.content,
a.cdt,
a.cano,
a.vw_cnt,
a.state,
u.uno,
u.nick article_nick,
u.photo article_photo,
t.tno,
t.name tag_name,
t.tag_color,
t.font_color
from
article a
inner join follow f on a.writer = f.fwing_no
inner join arc_tag at on at.arno = a.arno
inner join tag t on at.tno = t.tno
inner join user u on a.writer = u.uno
where
fwer_no = #{no}
union
select
a.arno,
a.title,
a.content,
a.cdt,
a.cano,
a.vw_cnt,
a.state,
u.uno,
u.nick article_nick,
u.photo article_photo,
t.tno,
t.name tag_name,
t.tag_color,
t.font_color
from
arc_tag at
inner join usr_tag ut on at.tno = ut.tno
inner join tag t on at.tno = t.tno
inner join article a on at.arno = a.arno
inner join user u on a.writer = u.uno
where
ut.uno = #{no}
) feed
order by feed.arno desc