본문 바로가기

SQL

[SQL 독학하기] 프로그래머스 오답풀이 - 조건에 맞는 회원수 구하기

Intro

분명 강의를 통해 공부할 때 굉장히 쉬웠고 홀로 교재를 풀어볼 때도 명쾌하게 넘어갔던 부분인데, 전혀 다른 문제에서 마주치니 알고있던 문법도 정확히 기억나지 않는 상황을 마주했다(이런건 알고있던 것이라고 표현하면 안된다).

이 문제에서 헷갈렸던 부분은 Where절에 여러 개 조건을 줄 때 작성문법, Oracle과 MySQL에서의 날짜 변환함수 및 날짜형식이다.

해당 문제 및 나의 답안, 해결방안은 아래와 같다.

 

Question

다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 USER_INFO 테이블입니다. USER_INFO 테이블은 아래와 같은 구조로 되어있으며 USER_ID, GENDER, AGE, JOINED는 각각 회원 ID, 성별, 나이, 가입일을 나타냅니다.

Column name Type Nullable
USER_ID INTEGER FALSE
GENDER TINYINT(1) TRUE
AGE INTEGER TRUE
JOINED  DATE FALSE

* GENDER 컬럼은 비어있거나 0 또는 1의 값을 가지며 0인 경우 남자를, 1인 경우는 여자를 나타냅니다.

USER_INFO 테이블에서 2021년에 가입한 회원 중 나이가 20세 이상 29세 이하인 회원이 몇 명인지 출력하는 SQL문을 작성해주세요.

 

Answer

Oracle 기준 내가 제출한 답안은 다음과 같다.

--Oracle--
SELECT COUNT(USER_ID) AS Users
  FROM USER_INFO
  WHERE JOINED BETWEEN TO_DATE('21/01/01','RR/MM/DD')
                   AND TO_DATE('21/12/31','RR/MM/DD')+1
        AND AGE BETWEEN 20 AND 29;

위 쿼리문을 실행했을 때, 2021년에 가입한 회원 중 20대인 회원은 총 97명으로 나타났다.

 

Oracle에서 답안을 작성할 때 WHERE절 조건을 쉼표(,)로 구분했을 때,

ㅠㅠ

위와 같은 오류가 발생했고 처음에는 뭐가 틀린건지 몰라 한참 화면을 들여다 봤다.

결과적으로, Oracle이든 MySQL이든 WHERE절에 여러 개의 조건을 연결할 때는 반드시 AND를 사용해야 한다는 것을 알았다. 

 

이후 MySQL에서 위 쿼리문을 실행하니,

마또오..(MySQL 또 오류)

위 문제를 해결하기 위해 Oracle과 MySQL에서 날짜를 다루는 함수에 대해 공부하였다.

 

Solutions

[Oracle의 날짜 변환함수]

Oracle에서 날짜 데이터를 검색할 때는 TO_DATE 함수를 사용한다.

TO_DATE 함수는 문자를 날짜형으로 출력할 때 활용하는데, 이는 기본 세션에 내장된 날짜 형식에 구애받지 않고 데이터를 검색하고 싶을 때 아주 유용하다.

예를 들어, 프로그래머스 Oracle의 기본 세션으로 설정된 파라미터를 확인하는 쿼리 및 결과는 아래와 같다.

SELECT * 
  FROM NLS_SESSION_PARAMETERS;

프로그래머스 Oracle 세션 정보 확인

실행 결과 중 NLS_DATE_FORMAT을 보면, 'DD-MON-RR'로 설정되어 있는 것을 볼 수 있다.

이는 현재 세션에서 원하는 날짜를 검색하려면 '일-월-연도' 순으로 검색해야 한다는 것을 의미한다.

물론 세션 정보를 확인해 기본 옵션대로 날짜 형식을 검색하는 것도 가능하지만, 국가마다 설정된 형식이 다르기도 하고 쿼리문을 작성할 때마다 파라미터를 확인하는 게 꽤나 번거롭다.

이럴 때 날짜 변환함수가 유용하게 쓰일 수 있는데, TO_DATE('검색날짜', '날짜형식')으로 작성하면 된다.

이렇게 작성한 쿼리는 세션에 날짜 형식이 어떻게 설정되었든 간에 관계없이 내가 작성한 날짜 형식으로 데이터를 검색한다.

 

[MySQL의 날짜 변환함수]

MySQL에서는 TO_DATE가 아닌 STR_TO_DATE 함수를 사용하며, STR_TO_DATE('검색날짜', '날짜형식')순으로 작성한다.

MySQL에서 날짜 변환함수를 사용한 답안은 아래와 같다.

--MySQL--
SELECT COUNT(USER_ID) AS Users
  FROM USER_INFO
  WHERE JOINED BETWEEN STR_TO_DATE('21/01/01','%Y/%m/%d')
                   AND STR_TO_DATE('21/12/31','%Y/%m/%d')
        AND AGE BETWEEN 20 AND 29;

 

 

여기서 MySQL과 Oracle이 날짜를 표현하는 형식이 다르다는 것을 알 수 있다.

각 DBMS의 날짜형식 구분은 아래와 같다.

날짜 구분 Oracle MySQL
년(Year) (4자리 연도) RRRR, YYYY
(2자리 연도) RR, YY
(4자리 연도) %Y
(2자리 연도) %y
월(Month) (전체 월 이름) MON
(숫자 월 이름) MM
(전체 월 이름) %M
(숫자 월 이름) %m
일(Day) DD %d
요일(Day) (전체 요일 이름) DAY
(짧은 요일 이름) DY
(전체 요일 이름) %W
(짧은 요일 이름) %a
주(Week) WW, IW, W %U
시(Hour) (12시간제) HH
(24시간제) HH24
(12시간제) %h
(24시간제) %H
분(Minutes) MI %i
초(Second) SS %s
밀리초(Millisecond) FF %f

 

이밖에 다른 분들이 다양한 날짜 함수를 활용해 MySQL에서 작성하신 답안 중 간결한 쿼리문 몇가지를 참고해봤다.

1) DATE_FORMAT 함수: 날짜를 지정한 형식으로 출력하는 함수

--MySQL--
SELECT COUNT(USER_ID) AS USERS
  FROM USER_INFO 
  WHERE DATE_FORMAT(JOINED, '%Y') = '2021'
        AND AGE BETWEEN 20 AND 29;

2) YEAR 함수 : 연도(0000~9999)를 반환하는 함수

--MySQL--
SELECT COUNT(USER_ID) AS USERS
  FROM USER_INFO
  WHERE YEAR(JOINED) = 2021 AND AGE BETWEEN 20 AND 29;

3) DATE 함수: 주어진 날짜 및 시간 데이터 중 날짜를 반환하는 함수

--MySQL--
SELECT COUNT(USER_ID) AS Users
  FROM USER_INFO
  WHERE JOINED BETWEEN DATE('2021-01-01')
                   AND DATE('2021-12-31')
        AND AGE BETWEEN 20 AND 29;

 

PS) 위에 작성된 방법 외에 쉽고 괜찮은 쿼리문이 있거나 내용상 틀린 부분이 있다면 댓글 부탁드립니다~! ( _ _ )