코딩테스트 준비/SQL 코테

[프로그래머스 SQL 고득점 KIT] 문제 풀이 (MySQL)

김긍수 2022. 3. 2. 22:03

https://programmers.co.kr/learn/courses/30/parts/17042

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

1. 모든 레코드 조회하기

 간단하게 모든 레코드를 조회하는 문제. SQL을 공부했다면 누구나 바로 풀 수 있는 문제다!

SELECT ANIMAL_ID, ANIMAL_TYPE, DATETIME, INTAKE_CONDITION, NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS
ORDER BY ANIMAL_ID ASC;

오름차순으로 정렬을 하는 경우, ORDER BY는 오름차순이 디폴트라 ASC는 생략해도 된다.

 

2. 역순 정렬하기

역순 정렬 또한 아주 간단히 풀 수 있는 문제다.

SELECT NAME, DATETIME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC;

ORDER BY 절에 역순으로 정렬할 컬럼명을 쓰고 DESC를 적어주면 역순 정렬로 결과가 출력된다.

 

3. 아픈 동물 찾기

해당하는 문자열과 같은 컬럼의 레코드를 출력하는 문제.

문자열은 = ''로 비교하면 된다.

SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION = 'Sick';

 

4. 어린 동물 찾기

해당 문자열이 아닌 레코드를 찾는 문제.

SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION != 'Aged'
ORDER BY ANIMAL_ID;

 

 

5. 동물의 아이디와 이름

이 문제 또한 1번 문제 오름차순으로 정렬하는 것과 똑같다.

 

6. 여러 기준으로 정렬하기

SELECT ANIMAL_ID, NAME, DATETIME
FROM ANIMAL_INS
ORDER BY NAME, DATETIME DESC;

ORDER BY 절에 작성한 컬럼명 순서대로 정렬이 정해진다.

 

7. 상위 n개 레코드

SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME
LIMIT 1;
SELECT NAME
FROM ANIMAL_INS
WHERE DATETIME=(select min(DATETIME) FROM ANIMAL_INS);

가장 보호소에 먼저 들어온 동물 1마리를 출력하기 위해서 2가지 방법으로 구현하였다.

먼저 LIMIT으로 결과값 개수를 정해주는 것이다.

두번째는 보호소에 가장 먼저 들어온 동물을 MIN()을 통해 1개를 뽑아준 다음 그것과 같은 DATETIME를 가진 레코드를 출력해주었다. 하지만 두번째 방법은 동일한 DATETIME을 가진 행이 많을 때 조건을 달리하면 원치않은 결과가 나올 수도 있을 것 같다. 조심하자~!

 

8. 최댓값 구하기

SELECT DATETIME AS '시간'
FROM ANIMAL_INS
ORDER BY DATETIME DESC
LIMIT 1;

결과 테이블의 컬럼명을 바꾸기 위해서는 AS를 사용한다. 

 

9. 최솟값 구하기

SELECT DATETIME AS '시간'
FROM ANIMAL_INS
ORDER BY DATETIME
LIMIT 1;

위 최댓값 구하기에서 정렬만 달리해주면 최소값을 찾을 수 있다. ORDER BY는 기본적으로 오름차순이므로 ASC를 붙이지 않아도 된다!

 

10. 동물 수 구하기

SELECT count(*) AS 'count'
FROM ANIMAL_INS;

동물 보호소에 들어온 동물의 수를 구하는 문제이다. 레코드 개수를 구하면 되는 문제이므로 count(*)로 전체 개수를 출력해주었다.

 

11. 중복 제거하기

SELECT count(DISTINCT NAME) 
FROM ANIMAL_INS
WHERE NAME IS NOT NULL;

문제를 읽고 굉장히 쉽다고 생각하고 했는데 틀린 채점이라고 나왔다. 무엇인지 계속 고민했는데

나는 SELECT DISTINCT count(*) 라고 써서 틀렸다.

DISTINCT는 중복을 제거하는 명령어이다. 또한 null이거나 null이 아닌걸 조건으로 삼을 때는 !=, =이 아니라 

IS NOT NULL, IS NULL로 해야한다.

 

11. 고양이와 개는 몇 마리 있을까

SELECT ANIMAL_TYPE, count(ANIMAL_TYPE) AS 'count'
FROM ANIMAL_INS
GROUP BY ANIMAL_TYPE
ORDER BY ANIMAL_TYPE;

이 문제도 쉽게 풀었는데, 계속 답이 틀리다고 나왔다😂

문법도 틀리지 않고 맞았는데 답이 틀린 이유는 정렬에 있었다. 그런데 문제에는 정렬 조건이 따로 없었는데.....

아무튼 질문게시판을 보고 수정해서 정답 처리하였다!

 

12. 동명 동물 수 찾기

SELECT NAME, count(NAME) as 'count'
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
GROUP BY NAME
HAVING count(NAME) >= 2
ORDER BY NAME;

1. 이름이 없는 동물은 집계에서 제외한다.

   WHERE절에 NAME IS NOT NULL을 작성해서 제외시켜주었다.

2. 동물 이름별 개수 조회, 2번 이상 사용된 이름 출력

   이름별 개수 조회를 위해서 GROUP BY절을 이용해서 묶어주었다. GROUP BY의 조건은 HAVING절을 이용한다.

 

13. 입양 시각 구하기(1)

SELECT HOUR(DATETIME), count(HOUR(DATETIME))
FROM ANIMAL_OUTS
WHERE HOUR(DATETIME) >= 9 and HOUR(DATETIME) <= 19
GROUP BY HOUR(DATETIME)
ORDER BY HOUR(DATETIME);

조금 어려웠다. 어떻게 HOUR을 차례대로 테이블에 넣을지...

DATETIME 포맷에 대해 까먹은 나의 실수이지만,,,, 프로젝트할때 엄청나게 많이 썼는데 그새 ㅠ_ㅠ

그래서 MySQL 시간/날짜 관련 함수들을 정리해보겠다.

 

1. 현재 날짜 반환

CURRENT_DATE, CURDATE()

 

2. 현재 시간 반환

CURRENT_TIME, CURTIME()

 

3. 현재 시간과 날짜 반환

CURRENT_TIMESTAMP, NOW()

 

4. DATE('2022-3-2'), TIME('8:43:10')

0을 입력하지 않아도 날짜로 인식한다.(ex 2022-03-02)

 

5. today = 2022-03-02

YEAR('2022-03-02') --- 2022반환

MONTHNAME('2022-03-02') --- 월(영어) 반환

MONTH('2022-03-02') --- 3 반환

WEEKDAY(today) --- 1

DAYNAME(today) --- 요일(영어)

DAY(today) --- 2

*** DAY는 0부터 시작한다. 0=월요일, 1=화요일, ...

 

6. HOUR( ), MINUTE( ), SECOND( ) = 주어진 날짜의 시,분, 초 반환

 

7. ADDDATE, DATE_ADD : 시간/날짜 더하기

SUBDATE, DATE_SUB : 시간/날짜 빼기

 

8. DATEDIFF(,) : 두 시간/날짜 간 일수차

TIMEDIFF(,) : 두 시간/날짜 간 시간차

 

9. LAST_DAY() : 해당 달의 마지막 날짜이다. 

 

10. DATE_FORMAT(시간, '형식')

형식 설명
%Y 년도 4자리
%y 년도 2자리
%M 월 영문
%m 월 숫자
%D 일 영문(1st, 2nd)
%d, %e 일 숫자(01~31)
%T hh:mm:ss
%r hh:mm:ss AM/PM
%H, %k 시 (~23)
%h, %l 시 (~12)
%i
%S, %s
%p AM/PM

 

14. 입양 시각 구하기(2)

또 엄청나게 틀린 문제.... 뭐가 문제인지 한참 생각했다... 문제를 잘 읽으면 0시부터 시작한다.

하지만 어떻게 해야할지 고민했는데 생각나지 않았다. 다른 블로그를 참고해보니 재귀테이블을 만들어야한다고 했다.

재귀테이블....은 또 어떻게 한담,,, 블로그를 참조하였다. SET 명령어를 사용하면 이 문제를 풀 수 있다.

SET 명령어에 대해 정리해보겠다.

* 어떤 변수에 특정 값을 할당하는 것(변수선언)이다.

[SET @data = 10], [SET @data := 10], [SELECT @data := 5] 이런 식으로 표현이 가능하다. 하지만 두번쨰 := 를 사용하는 것이 좋다. MySQL에서 대입연산자로 사용되기 때문이다.

SET @hour := -1; // 변수 선언
SELECT (@hour := @hour + 1) as 'HOUR', // 0부터 출력 
        (SELECT count(*)
        FROM ANIMAL_OUTS 
        WHERE HOUR(DATETIME) = @hour) as COUNT // @hour 값과 같은 레코드 개수
FROM ANIMAL_OUTS
WHERE @hour < 23;

작성해보니 SET명령어를 알고 있었다면 순조롭게 풀 수 있었을 것 같다. 다음에 SET을 사용하는 문제가 나오면 자신있게 풀 수 있을 것이다!

 

IS NULL 

 

IFNULL : 해당 컬럼의 값이 NULL을 반환할때, 다른 값으로 출력할 수 있도록 하는 함수이다.

ex) IFNULL(name, '이름없음')

 

IF : IF조건

ex) IF(name is null, '이름없음', NAME) // name is null이 참인 경우 '이름없음'으로, 거짓인 경우 NAME 데이터 값이 출력된다.

 

CASE 문

CASE 

     WHEN 조건식 1 THEN 식1

     WHEN 조건식 2 THEN 식2

     ELSE 나머지 식

END

 

1. 이름이 없는 동물의 아이디

SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NULL;

NULL 값이 있는 레코드를 조회하는 SQL문이다.

!=를 사용하지 않도록 조심해야한다.

 

2. 이름이 있는 동물의 아이디

SELECT ANIMAL_ID
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
ORDER BY ANIMAL_ID;

NULL이 아닌 행을 찾으려면 IS NOT NULL 을 사용하면 된다.

 

3. NULL 처리하기

SELECT ANIMAL_TYPE, IFNULL(NAME, 'No name') as NAME, SEX_UPON_INTAKE
FROM ANIMAL_INS;