Oracle SQL 실전문제 풀이 (1)

반응형

https://www.hackerrank.com/challenges/weather-observation-station-5/problem

가장 긴 이름을 가진 CITY와 가장 짧은 이름을 가진 CITY, 총 2가지 CITY를 글자수와 함께 출력하라는 문제였다. 만약 족너에 해당되는 도시가 2개 이상이라면 알파벳 오름차순에 따라서 정렬 후 출력.

STATION
Field Type
ID Number
CIYT Varchar2(21)
이하 생략

 

문제에 주어진 풀이 예시를 보면 ABC 3 \n PQRS 4 이런 식으로 제시되었다. 특이한 점은 두개의 쿼리로 나눠 작성해도 답으로 인정된다는 것. 생각해보니 정렬 기준이 2가지가 필요한데 서로 상관관계가 없기 때문에 한가지 쿼리로 작성하면 굉장히 비효율적으로 진행될 것 같아서 나눠 작성하라는 듯하다.

 

방법1 : 그룹함수 사용하기

- select CITY, LENGTH(CITY) from STATION
- 우선 CITY와 CITY의 길이를 출력할 수 있는 쿼리를 작성해본다.

- where LENGTH(CITY) = (select MIN(LENGTH(CITY)) from STATION)
- 중첩쿼리 사용하여 글자수가 가장 작은 것으로 제한하는 쿼리. 이제 위의 쿼리문과 합치고 알파벳 오름차순으로 정렬해보자.

- select CITY, LENGTH(CITY) from STATION where LENGTH(CITY) =
(select MIN(LENGTH(CITY)) from STATION) order by CITY
- 완성되었으나 이대로 실행하게 되면 CITY에서 최소 글자수인 녀석들이 2개 이상 출력될 수 있다. 즉 인덱스를 기준으로 2 이상인 녀석들은 출력시키면 안된다.

- select CITY, LENGTH(CITY) from STATION
 
where rownum=1 and LENGTH(CITY) = (select MIN(LENGTH(CITY)) from STATION) order by CITY
- where 절에 rownum을 활용하여 개수를 1개로 제한시켰다. 그런데... 해커랭크에서 실행결과 오답이 나온다. 찾아보니 rownum은 order by 절 이전에 매겨지는 값이기 때문에 사용하고 싶다면 다시 한번 중첩쿼리를 활용해야 할 것 같다.

- select * from
  (select CITY, LENGTH(CITY) from STATION
      where LENGTH(CITY) = (select MIN(LENGTH(CITY)) from STATION) order by CITY)
where rownum=1
- 정렬까지 진행한 후 쿼리를 실행했기에 이번엔 제대로 실행되었다.

- select * from
  (select CITY, LENGTH(CITY) from STATION
      where LENGTH(CITY) = (select MAX(LENGTH(CITY)) from STATION) order by CITY)
where rownum=1
- 구조가 같기 때문에 min함수를 max함수로 바꿔주기만 하면 된다.

 

방법2 : 정렬로만 풀어보기

- 그룹함수 (max, min)이 갑자기 기억이 안난다고 가정해보자.. 정렬만 이용하여 문제를 풀어보자.

- select CITY, LENGTH(CITY) from STATION order by LENGTH(CITY), CITY / 글자수를 오름차순으로 정렬한 이후 알파벳 오름차순으로 다시 정렬했다. 이 쿼리의 맨 처음 값은 글자수가 가장 적으면서 알파벳 순서로도 가장 앞에 오는 값일 것이다.

- select CITY, LENGTH(CITY) from STATION order by LENGTH(CITY) desc, CITY / 글자수를 내림차순으로 정렬한 이후 알파벳 오름차순으로 정렬했다. 이 쿼리의 맨 처음 값은 글자수가 가장 많으면서 알파벳 순서로 가장 앞에 오는 값이다. 이제 rownum을 활용하여 추출해낸 다음 위 쿼리와 합쳐주기만 하면 된다.

- select * from (select CITY, LENGTH(CITY) from STATION order by LENGTH(CITY), CITY) where rownum=1 / 방법 1처럼 정렬 이후 인덱스를 사용하기 위하여 중첩쿼리를 사용

- select * from (select CITY, LENGTH(CITY) from STATION order by LENGTH(CITY) desc, CITY) where rownum=1 / 마찬가지 원리로 중첩쿼리 사용

 

풀어놓고 보면 그렇게 어려운 문제는 아니었지만 해커랭크 문제 앞부분에 출제되어서 약간 애먹었던 문제이다. 더불어 처음 이 문제를 풀 때에는 '두개 쿼리로 나눠 작성해도 됨' 이 조건을 대충봐서 한개의 쿼리로 작성하느라 더욱 진이 빠졌다. 어찌저찌 문제를 풀어서 맞추긴 했지만, 다시 검토해보니 해커랭크 테스트 데이터 셋을 살펴보니 내 풀이가 틀렸다는 것을 깯달았다. 항상 느끼지만 문제를 제대로 읽고, 문제 풀이 조건을 꼼꼼히 검토해야겠다. (메타인지 일 좀 해라!!)