0. 들어가며
앞선 글에서
8월에 한 번 구매한 고객 중 9월 달에 구매한 이력이 없는 고객은?
이라는 질문에 대답을 하는 쿼리를 짰다.
이 때는 답을 내는 것에 가장 우선적인 목적을 두었다면,
이번에는 이전보다 코드의 가독성을 높이고, 보다 간단한 쿼리를 작성하는 것에 초점을 맞추었다.
1. 처음 작성한 쿼리의 구조
select b.customer_id
from (
select customer_id, (extract(MONTH from pay_date)::bigint) as mon , count(extract(MONTH from pay_date)) as cnt
from mysql_test
group by customer_id, mon
having (extract(MONTH from pay_date)::bigint) = 8 and count(extract(MONTH from pay_date)) = 1
) as data
left join mysql_test as b
on data.customer_id = b.customer_id
group by b.customer_id
having count(b.customer_id) <2
처음 작성한 쿼리를 분석해보자.
서브쿼리를 from절(인라인뷰)에 사용하는 쿼리는
8월달에 구매했는지, 1건을 구매했는지
두 조건을 동시에 만족하는 데이터를 추출했다.
서브쿼리만을 실행하면 아래와 같은 데이터가 나온다.
이 데이터를 기본 mysql_test 테이블과 customer_id를 기준으로 left join했다.
이를 통해 9월달에 주문한 기록이 있다면, 위 데이터와 함께 customer_id가 여러번 나오도록 유도했다.
따라서 같은 customer_id가 여러개인 것을 제거하면,
우리의 목표를 달성하는 방식을 썼다.
(구구절절한 설명? 다른사람을 이해시키는데 좋지 않다..)
좋은 설명이란 간결하고 명료한 것...
코드도 다르지 않다..
좋은 코드란 간결하고 명료한 것...
2. 리팩토링한 쿼리
select a.customer_id
from (
select customer_id, count(*) as cnt
from mysql_test
where extract(month from pay_date) = 8
group by customer_id
having count(*) = 1
) as a
where customer_id not in (select distinct(customer_id)
from mysql_test
where extract(month from pay_date) = 9)
리팩토링한 쿼리는 이전과 비교했을 때 두 가지 특징이 있다.
1. JOIN을 사용하지 않았다.
JOIN을 사용하지 않음으로 테이블 구조를 머릿 속에서 보다 쉽게 그릴 수 있다.
이는 내가 짠 쿼리를 다시 보는 상황, 타인이 내가 짠 쿼리를 다시 보는 상황
모두에서 도움이 된다.
특히 조인기능을 모르는 이에게 더욱 친절한 쿼리가 될 것이다.
(보통 where절을 배운이후에 join절을 가르친다.)
2. 가독성을 높였다.
이전 쿼리와 리팩토링한 쿼리의 인라인절을 비교하면 우선 추출하고자 하는 데이터컬럼 수가 줄었다.
지난 쿼리에서는 맞게 작업을 하고 있는지 확인차원에서 넣은 mon, cnt 컬럼이 있다.
이를 통해 having절의 길이도 줄일 수 있었다.
where 절 안에 있는 서브쿼리는
9월 달에 구매기록이 있는 고객 ID를 추출한다.
Where 절을 통해 위에서 추출된 고객 ID 를 제외하는 방식을 사용해 가독성을 높였다.
3. 얻은 것과 해나갈 것
같은 결과물을 내지만, 성능과 코드의 가독성을 높이는 리팩토링이란 용어를
쭈니를 통해 자연스레 접했다.
실제로 리팩토링을 처음부터 끝까지 혼자 고민해본 것은 처음이다.
코드를 더욱 직관적으로 이해하는데 주안점을 두었다.
처음 짠 쿼리는 직관성보다는 제대로 된 결과물이 산출되는지가 가장 큰 이슈였다.
이번 쿼리 리팩토링을 통해 조금 더 쉬운 문제접근방식과 가독성에 집중해 볼 수 있었다.
이뿐만 아니라 R 사용자 입장에서 똑같은 데이터가 주어져 있을 때
이를 R코드로 어떻게 구현해낼 것인지도 고민하게 됐다.
다음 게시글은 위의 쿼리 결과물을 R로 구현하는 내용을 쓰려고 한다.
'SQL ' 카테고리의 다른 글
조금 더 현실적인 문제해결을 위한 SQL 쿼리짜기 2탄 - R을 곁들인 코드 (0) | 2022.01.17 |
---|---|
조금 더 현실적인 문제 해결을 위한 SQL 쿼리짜기 (0) | 2021.12.19 |
[TIL] window function partition in SQL (0) | 2021.12.15 |
TestDome SQL리뷰 및 면접경험 (2) | 2021.12.08 |
SUBSTRING(), REPLACE(), POSITION() and COALESE() (0) | 2021.04.23 |