DB/SQL

세무민의 코딩일기 : DB 공부할 때 팁! [Group By와 Order By만 잘해도 절반은 먹고 간다. ]

세기루민 2021. 5. 7. 00:57
728x90

인턴을 하면서 느낀점은 

프로그램의 성능 최적화는 DB에서 Select 하는 과정을 어떻게 하는지가 중요한거 같다. 

일반적으로 Service에서 값을 원하는 형태로 변형하여 넘겨도 되지만 

쿼리로 제작할 수 있다면 제일 베스트이다. 

여기서 가장 중요한건 서브쿼리, 내장함수도 중요하지만 

기본적인 Group by와 Order By의 중요성이다. 

우선 이론적인 학습을 해보자.

1. GROUP BY 

그룹이라는 말 처럼 AVG, SUM과 같이 전체 값을 연산했을 때 주로 사용되는데 

일반적으로 여러개의 행을 이용하여 통계적인 값을 추출할 수 있다. 

2. ORDER BY

ORDER BY는 조회하려는 데이터를 정렬로 자주 사용되곤 한다. 

일반적으로 쿼리를 제작하다보면 Group by 형식 오류를 자주 접하는 사람들이 있다. 

이 경우에는 Select에 지정한 컬럼을 모두 포함했는지 확인해야 한다. 

최근에 동료 인턴의 쿼리를 도와주면서 아쉬웠던 부분이 바로 이 문제였다. 

예를 들어보면 

SELECT A~~~~
FROM(
	SELECT B~~~~~ 
    FROM
    )
GROUP BY C~~~

위와 같다고 가정했을 때 

우선 서브쿼리에 대한 별칭을 A부분에서 사용가능하다는 것을 알 수 있는데 

해당 SELECT에 뽑으려는 모든 데이터를 C에 같이 나열해줘야 한다. 

서브쿼리를 이용하다보면 오류가 어디서 발생했는지 확인하기 어려운데

이럴땐 스크립트로 돌려보면서 오류를 찾으면 된다.


추가적으로 오라클을 이용하면서 TO_DATE와 TO_CHAR를 자주 사용하는데 

혹시 날짜값을 TO_CHAR를 이용할 때 1~7까지의 숫자로 반환된다는 것을 알고 있는가?

날짜값을 TO_CHAR로 할 경우 숫자로 반환되고 이를 이용하여 결과를 도출할 수 있다. 

나중에 기회가 된다면 한번 이용해보는걸 추천하며

오늘 팀 프로젝트에서 해당 월에 대한 첫번째 날부터 마지막 날을 구하는 쿼리를 작성했다. 

select
     TO_CHAR(LAST_DAY('20200901')),
     ADD_MONTHS(FRISTDAYS, -1) AS 첫번째날
    ,TO_CHAR(LAST_DAY('20200901') - LASTDAYS) AS 마지막날
FROM (
      SELECT TO_CHAR(LAST_DAY('20200901'), 'DD') AS LASTDAYS
      ,TO_CHAR(TRUNC(TO_DATE('20200901'), 'MM')) AS FRISTDAYS
      FROM DUAL
  );

 

원래는 SYSDATE를 이용하여 구현하고 현재 사용중인데 

위의 쿼리는 내가 끄적인 테스트 쿼리다. 

아마 위의 쿼리를 돌리면 31, 2020/08/01, 2020/08/31 이라는 값을 확인할 수 있다. 

여기서 포인트는 LAST_DAY, TRUNC이다.

LAST_DAY는 해당 년월일에 대한 마지막 일을 출력해준다. 

TRUNC는 다양한 용도로 사용되는데 절사로 이용하여 연도로 이용할 땐 1일에 대한 값을 도출하기 위해 사용한다. 

무튼 LAST_DAY와 TRUNC를 이용하면 도움이 된다. 


마지막으로는 WITH AS를 이용하는 것이다. 

WITH AS를 이용한다고 하면 당황스러울 것이다. 

사실 WITH AS로 만들게 되면 자칫 쿼리도 길어지고 양이 많아지게 되는데 

세기무민(가장 일 처리를 많이 한 직원) 80.9%
세무민쓰(가장 업무 대비 성과가 좋은 직원) 77.4%

예를 들어서 위의 표처럼 값을 추린다고 가정해보자.

이럴 때 어떻게 표현할 것인가?

Service 로직에서 수정해도 무관하지만 

With As와 Union을 이용한다면? 

내가 원하는 값을 서브쿼리로 정리한 뒤 붙여주면 쉽게 끝난다.

with tmp1 as(
	select A~~~~
    from B~~~~
	group by c~~~~
), tmp2 as(
	select A2~~~~
    from B2~~~~
	group by c2~~~~
)
select * from tmp1
UNION all
select * from tmp2

실제로 사용하는 쿼리는 보안상 이용할 수 없어서 예시를 표현해봤다. 

실제 원하는 값을 추출하기 위해서는 값을 union을 이용해서 붙여주는 것도 하나의 방법이다. 

실제 사용했을 땐 max값을 이용할 때 group by를 이용하지 않고

over(PARTITION BY ~)를 이용하여 간편하게 구현했다.

무튼 위에 경우를 말한 이유는 동료 인턴의 쿼리를 도와주다가

위에처럼 원하는 값을 어떻게 해야할 지 모르길레 위와 같은 방법으로 붙여보라고 추천했고 

실제 그렇게 진행했다.

사실 위에 경우가 무조건 맞다고는 할 수 없다.

그렇지만 위의 경우처럼 용어들을 알아 두신다면

나중에 오라클을 이용하면서 도움이 되지 않을까 싶어서 작성해봤습니다.

사실 실제 쿼리를 작성하지 않았지만 추후에 임의의 테이블을 만들어서 다시 포스팅 해보겠습니다.

다음에는 더 좋은 포스팅으로 찾아오겠습니다.

728x90