이 문제에서는 특정 컬럼을 기준으로 상위 3개의 값을 보여주어야 하는 문제이다. 또한 널값을 이용해야해서 join에 대한 개념이 잘 안 잡힌 나로서 좀 어려웠다.
상위 n개의 데이터만 뽑으려면 ROWNUM이라는 명령어를 사용하면 된다. 이걸 사용하면 해당 행의 값을 출력할 수 있고, 부등호를 사용하면 범위로 값을 나타낼 수도 있다.
SELECT NAME
FROM ANIMAL_INS
WHERE ROWNUM <= 3;
이렇게 위의 3개의 값만 나오게 된다.
그런데 우리는 큰값 3개나 작은 값 3개 처럼 정렬후 데이터를 뽑고싶을 수 있다. 이 때 우리는 다음과 같이 코드를 하면 된다고 생각 할 수 있다.
SELECT NAME
FROM ANIMAL_INS
WHERE ROWNUM <= 3;
ORDER BY NAME DESC
하지만 SQL을 ORDER명령어보다 WHERE을 먼저 실행하기 때문에 3값을 먼저 뽑고 정렬을 하게 되어 원하는 값을 못 얻게 된다.
그래서 SUBQUERY로 FROM에 정렬을 한 결과를 만들고 거기서 다시 3개의 값을 뽑아야한다.
SELECT NAME
FROM
(
SELECT NAME
FROM ANIMAL_INS
ORDER BY NAME DESC
)
WHERE ROWNUM <= 3;
이렇게 해야 우리가 원하는 값을 찾을 수 있다.
SELECT AI.NAME, AI.DATETIME
FROM(
SELECT AI.NAME, AI.DATETIME
FROM ANIMAL_INS AI, ANIMAL_OUTS AO
WHERE AI.ANIMAL_ID = AO.ANIMAL_ID(+)
ORDER BY AI.DATETIME
)
WHERE ROWNUM <= 3;
다음과 같이 쿼리를 짰는데 오류가 떴다.
AI.DATETIME을 찾을 수 없다는 것이다. 그래서 SUBQUERY에서 두 쿼리를 독립적이라는 것을 깨닫고 AI와 AO의 컬럼이 합쳐진 컬럼이므로 AI와 AO는 붙이면 안된다는 것을 깨달았다.
해당 단계에서 최종 쿼리
SELECT NAME, DATETIME
FROM(
SELECT AI.NAME, AI.DATETIME
FROM ANIMAL_INS AI, ANIMAL_OUTS AO
WHERE AI.ANIMAL_ID = AO.ANIMAL_ID(+)
ORDER BY AI.DATETIME
)
WHERE ROWNUM <= 3;
JOIN에서 NULL값을 표시하기 위해서는 OUTER JOIN을 사용해야한다. 이것까지는 인지를 했지만, '그럼 두 테이블중 어디에 넣어야하지?'라는 고민을 했다.
생각을 해보니 지금 나는 ANIMAL_INS에는 있고 ANIMAL_OUTS에는 없는 애들을 찾아야한니까 NULL값이 ANIMAL_OUTS에 있어야한다고 생각했고 그래서 다음과 같이 쿼리를 짰다.
SELECT NAME, DATETIME
FROM(
SELECT AI.NAME, AI.DATETIME
FROM ANIMAL_INS AI, ANIMAL_OUTS AO
WHERE AI.ANIMAL_ID = AO.ANIMAL_ID(+)
ORDER BY AI.DATETIME
)
WHERE ROWNUM <= 3;
이제 입양을 가지 못한 애들을 걸러주기위해 조건을 걸어야한다. 그래서 AO에서 NULL이 뜨는 애들을 골라야하는데 어떤 컬럼을 사용해야하는 지를 몰랐다. JOIN을 사용하면 출력이 어떤 식으로 되는 지를 정확히 몰라서 그랬다.
JOIN을 사용하면 해당 테이블이 모두 합쳐진다. JOIN에 사용된 컬럼만 하나가 되고 나머지는 이름이 같더라도 독립적인 컬럼이 따로 생긴다. 그리고 JOIN에 사용된 애들만 겹치지 않는 데이터에 NULL이 생긴다(다른 컬럼은 다 독립적이어서 NULL이 생길 이유가 없다). 나는 이것을 인지하지 못해서 IS NULL을 어떤 컬럼에 걸어야 하는 지를 몰랐다.
SELECT NAME, DATETIME
FROM(
SELECT AI.NAME, AI.DATETIME
FROM ANIMAL_INS AI, ANIMAL_OUTS AO
WHERE AI.ANIMAL_ID = AO.ANIMAL_ID(+) AND AO.ANIMAL_ID IS NULL
ORDER BY AI.DATETIME
)
WHERE ROWNUM <= 3;
JOIN에 사용한 컬럼 IS NULL을 해주면 된다.
SELECT NAME, DATETIME
FROM(
SELECT AI.NAME, AI.DATETIME
FROM ANIMAL_INS AI, ANIMAL_OUTS AO
WHERE AI.ANIMAL_ID = AO.ANIMAL_ID(+) AND AO.ANIMAL_ID IS NULL
ORDER BY AI.DATETIME
)
WHERE ROWNUM <= 3;
아직 입양되지 않은 날짜기준 먼저온 3명의 개를 출력이 가능하다.
이 문제는 JOIN의 개념과 상위 N개 출력하기 방법을 잘 몰라서 풀지 못한거 같다.