SQL 문법에는 JOIN이 존재한다.
가장 많이 사용해는 조인
SELECT <열 목록>
FROM <첫 번째 테이블>
INNER JOIN <두 번째 테이블> ON <조인 조건>
[WHERE 검색 조건]
#INNER JOIN은 JOIN이라고만 써도 인식함

외부 조인은 한쪽에만 데이터가 있어도 결과가 나온다
SELECT <열 목록>
FROM <첫 번째 테이블(LEFT 테이블)>
<LEFT | RIGHT| FULL> OUTER JOIN <두 번째 테이블(RIGHT 테이블)>
ON <조인 조건>
[WHERE 검색 조건]


좌측 테이블은 가져오되 조인 가능한 것은 붙이고, 조인 불가능 한 것은 NULL로 채운다.
한쪽 테이블의 모든 행과 다른 쪽 테이블의 모든 행을 조인
상호 조인 결과 행의 개수 = 두 테이블의 각 행의 개수의 곱
- 카티션 곱 (CARTESIAN PRODUCT)라고도 함

자체 조인은 자기 자신과 조인하므로 1개의 테이블을 사용
SELECT <열 목록>
FROM <테이블> 별칭A
INNER JOIN <테이블> 별칭B
[WHERE 검색 조건]

서브쿼리란 다른 쿼리 내부에 포함되어 있는 select 문을 의미
SELECT *
FROM main_table_55
WHERE target_id in (
SELECT id
FROM sub_table_noindex_55
WHERE id < 500
);
책이 받은 좋아요 개수를 보여주기 위한 query
SELECT count(*)
FROM book_likes
WHERE book_id = {대상 책 아이디}

만약 block 테이블이 다음과 같다면
책의 좋아요 갯수를 계산하는데, 내가 차단한 사용자의 좋아요는 집계하지 않는 query (if 책의 아이디: 3, 내 아이디: 2)
SELECT count(*)
FROM book_likes
WHERE book_id = 3 and member_id not in (SELECT target_id FROM block WHERE owner_id = 2)
또는
SELECT count(*)
FROM book_like as bl
INNER JOIN block as b
ON bl.user_id <> b.target_id and b.owner_id = 2
WHERE bl.book_id = 3;
또는
SELECT count(*)
FROM book_like as bl
LEFT JOIN block as b
ON bl.user_id = b.target_id and b.owner_id = 2
WHERE bl.book_id = 3 and b.target_id is null;
로 작성 가능하다.
쿼리를 작성할 때 N : M 관계로 인해 매핑 테이블이 추가된 경우
SELECT *
FROM book
WHERE id in (SELECT book_id FROM book_hash_tag WHERE hash_tag_id = (SELECT id FROM hash_tag WHERE name = 'UMC"));
책의 목록을 최신순으로 조회하는 query
SELECT * FROM book ORDER BY created_at desc;
좋아요 개수 순으로 목록 조회하는 query
SELECT *
FROM book as b
JOIN (SELECT count(*) as like_count FROM book_likes GROUP BY book_id) as likes
ON b.id = likes.book_id
ORDER BY likes.like_count desc;
목록 조회는 한번에 가져오면 엄청난 렉이 발생하므로 끊어서 가져와야함
직접 페이지 번호를 찾아내어 이동하는 페이징
SELECT *
FROM book
ORDER BY likes desc
LIMIT 10 OFFSET 0;
limit를 통해 한 페이지에서 보여줄 데이터의 개수를 정하고 offset으로 몇 개를 건너 뛸지를 정한다.
페이지 x번에 대해 한 페이지에 y개를 보여주는 query
SELECT *
FROM book
ORDER BY likes desc
LIMIT y OFFSET (x - 1) * y;
offset paging의 단점은 페이지가 뒤로 갈 수록 넘어가는 데이터가 많아져 성능 상의 이슈가 있고 사용자가 1페이지에서 2페이지로 넘어갈 때, 게시글이 6개가 추가가 되는 문제가 있다.
커서로 무언가를 가르켜 페이징을 하는 방법
커서는 마지막으로 조회한 콘텐츠
마지막으로 조회한 책의 좋아요가 20이라면?
SELECT *
FROM book
WHERE book.likes < 20
ORDER BY likes desc
LIMIT 15;
이런 형태가 되고 실제로는 마지막으로 조회한 책의 아이디를 가져와
SELECT *
FROM book
WHERE book.likes < (SELECT likes FROM book WHERE id = 4)
ORDER BY likes desc
LIMIT 15;
가 된다.
하지만 좋아요가 0개인 게시글이 400개이고, 공교롭게 마지막으로 조회한 책의 좋아요가 0개라면, 다음 페이지에 책이 목록으로 조회가 되지 않는 문제가 있다.
이를 위해 정렬 기준이 하나 더 있어야 한다.
SELECT * FROM book as b
JOIN (SELECT count(*) as like_count FROM book_likes GROUP BY book_id) as likes
on b.id = likes.book_id
WHERE likes.like_count < (SELECT count(*) FROM book_likes WHERE book_id = 3)
ORDER BY likes.like_count desc, b.created_at desc limit 15;