본문 바로가기

SQL

프로그래머스 SQL 고득점 Kit 풀이 - SELECT 편

SELECT

Lv1.조건에 맞는 회원 수 구하기 

https://school.programmers.co.kr/learn/courses/30/lessons/131535

 

프로그래머스

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

programmers.co.kr

풀이

SELECT COUNT(*)
FROM USER_INFO
WHERE AGE >= 20 AND AGE <=29 AND DATE_FORMAT(JOINED ,"%Y") = "2021"

 
이 문제는 JOINED -> "2021-03-09" 에서 "2021"만 추출하는게 키 포인트 
 
MySQL의 경우 날짜를 문자열로 변환할 때 DATE_FORMAT(날짜 , 출력 형식) 을 사용하면된다.
ex)

SELECT DATE_FORMAT('2023-05-03 20:12:42', '%Y-%M-%D')


--  2023-05-03 이 출력된다.

 
반대로 문자열을 날짜로 변환하는 경우 STR_TO_DATE(문자 , 출력 형식)을 사용한다.
ex)

SELECT STR_TO_DATE('20230503', '%Y-%M-%D')

-- 20230503이라는 문자열이 2023-05-03의 date 형태로 출력된다.

Lv1.상위 n개 레코드

https://school.programmers.co.kr/learn/courses/30/lessons/59405

 

프로그래머스

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

programmers.co.kr

정답

SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME
LIMIT 1

ORDER BY는 결과 집합을 오름차순 또는 내림차순으로 정렬되는데 사용된다. 
ODDER BY는 기본적으로 레코드를 오름차순으로 정렬한다. (ASC) . 내림차순으로 정렬하고 싶다면 다음과 같이 DESC를 적어주면된다.

SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME DESC 
LIMIT 1

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

https://school.programmers.co.kr/learn/courses/30/lessons/59404

 

프로그래머스

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

programmers.co.kr

정답

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

ORDER BY는 다중 정렬 할 때 , 왼쪽부터 순차적으로 정렬되기 때문에 순서를 고려해야한다.
ex)

ORDER BY column1 , coulumn 2 DESC

라고 한다면 column1을 기준으로 먼저 내림 차순 정렬 후  ,  column1이 같은 경우에 한해서만 column2를 기준으로 내림차순으로 정렬한다. 
 


Lv1.동물의 아이디와 이름 

https://school.programmers.co.kr/learn/courses/30/lessons/59403

 

프로그래머스

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

programmers.co.kr

정답

SELECT ANIMAL_ID, NAME 
FROM ANIMAL_INS
ORDER BY ANIMAL_ID

 


Lv1. 어린 동물 찾기

https://school.programmers.co.kr/learn/courses/30/lessons/59037

 

프로그래머스

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

programmers.co.kr

정답

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

Lv1. 아픈 동물 찾기

https://school.programmers.co.kr/learn/courses/30/lessons/59036

 

프로그래머스

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

programmers.co.kr

정답

SELECT ANIMAL_ID, NAME 
FROM ANIMAL_INS
WHERE INTAKE_CONDITION = 'Sick'
ORDER BY ANIMAL_ID

Lv1. 역순 정렬하기

https://school.programmers.co.kr/learn/courses/30/lessons/59035

 

프로그래머스

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

programmers.co.kr

정답

SELECT NAME , DATETIME 
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC

Lv1. 조건에 맞는 도서 리스트 출력하기

https://school.programmers.co.kr/learn/courses/30/lessons/144853

 

프로그래머스

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

programmers.co.kr

정답

SELECT BOOK_ID , DATE_FORMAT(PUBLISHED_DATE, "%Y-%m-%d") AS DATE_FORMAT
FROM BOOK
WHERE DATE_FORMAT(PUBLISHED_DATE, "%Y") = "2021" AND CATEGORY = "인문"
ORDER BY PUBLISHED_DATE

 
SELECT 절에서  DATE_FORMAT(PUBLISHED_DATE, "%Y-%m-%d") 이런식으로 출력형식을 지정해주지 않고 PUBLISHED_DATE만 적었다면 다음과 같이 결과가 나오니 주의하자.

 
그리고 출력 형식에 m과 d를 대문자로 작성했다면 아래와 같이 영문으로 출력되는것을 볼 수 있다. 이는 출력형식이 뭐냐에 따라 출력값이 다르기 때문이다.

 
 DATE_FORMAT 의 두번째 파라미터 값에 출력값을 넣었을때 어떤 값이 반환되는지 확인해보자.
https://www.w3schools.com/sql/func_mysql_date_format.asp

 

MySQL DATE_FORMAT() Function

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

%a 요일의 약어 (Sun부터 Sat까지)
%b 월의 약어 (Jan월부터 Dec월까지)
%c 숫자로 된 월 (0부터 12까지)
%D 숫자로 된 월의 날짜, 뒤에 접미사가 붙음 (1st, 2nd, 3rd, ...)
%d 숫자로 된 월의 날짜 (01부터 31까지)
%e 숫자로 된 월의 날짜 (0부터 31까지)
%f 마이크로초 (000000부터 999999까지)
%H 시간 (00부터 23까지)
%h 시간 (00부터 12까지)
%I 시간 (00부터 12까지)
%i 분 (00부터 59까지)
%j 해당 년도의 몇 번째 날인지 (001부터 366까지)
%k 시간 (0부터 23까지)
%l 시간 (1부터 12까지)
%M 월의 전체 이름 (1월부터 12월까지)
%m 숫자로 된 월 (00부터 12까지)
%p AM 또는 PM
%r 12시간 형식으로 표시된 시간 (hh:mm:ss AM/PM)
%S 초 (00부터 59까지)
%s 초 (00부터 59까지)
%T 24시간 형식으로 표시된 시간 (hh:mm:ss)
%U 일요일이 한 주의 첫 날인 주차 (00부터 53까지)
%u 월요일이 한 주의 첫 날인 주차 (00부터 53까지)
%V 일요일이 한 주의 첫 날인 주차 (01부터 53까지). %X와 함께 사용됨
%v 월요일이 한 주의 첫 날인 주차 (01부터 53까지). %x와 함께 사용됨
%W 요일의 전체 이름 (일요일부터 토요일까지)
%w 일요일이 0, 토요일이 6인 요일 (0부터 6까지)
%X 일요일이 한 주의 첫 날인 주차의 연도. %V와 함께 사용됨
%x 월요일이 한 주의 첫 날인 주차의 연도. %v와 함께 사용됨
%Y 네 자리 숫자로 된 연도
%y 두 자리 숫자로 된 연도

Lv1. 인기있는 아이스크림

https://school.programmers.co.kr/learn/courses/30/lessons/133024

 

프로그래머스

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

programmers.co.kr

정답

SELECT FLAVOR
FROM FIRST_HALF
ORDER BY TOTAL_ORDER DESC , SHIPMENT_ID

 


Lv1. 흉부외과 또는 일반외과 의사 목록 출력하기

https://school.programmers.co.kr/learn/courses/30/lessons/132203

 

프로그래머스

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

programmers.co.kr

정답

SELECT DR_NAME , DR_ID , MCDP_CD , DATE_FORMAT(HIRE_YMD ,"%Y-%m-%d") as HIRE_YMD
FROM DOCTOR
WHERE MCDP_CD = "CS" OR MCDP_CD = "GS"
-- WHERE  MCDP_CD IN ('CS', 'GS')
ORDER BY HIRE_YMD DESC , DR_NAME

Lv1. 강원도에 위치한 생산공장 목록 출력하기

https://school.programmers.co.kr/learn/courses/30/lessons/131112

 

프로그래머스

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

programmers.co.kr

정답

SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "강원도%"
ORDER BY FACTORY_ID

이 문제의 키포인트는 "강원도 정선군 남면 칠현로 679" 라고 문자열이 주어지면 "강원도" 라는 부분이 있는가 없는가를 확인하는 것이다.

 

이때 LIKE  연산자를 이용하면 된다.  LIKE 구문은 where절에서 많이 사용되며 %와 언더바(_)를 이용해서 부분적으로 일치하는 값을 조회할 수 있다.

 

%은 문자열의 길이가 제한이 없는 것

1) %가 하나일 경우

-- FOOD_FACTORY 테이블의 ADDRESS 에서 "강원도" 로 시작하는 모든 공장 조회
SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "강원도%"


-- FOOD_FACTORY 테이블의 ADDRESS 에서 "강원도" 로 끝나는 모든 공장 조회
SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "%강원도"


2) %가 문자를 기준으로 앞 뒤로 사용될 때

-- FOOD_FACTORY 테이블의 ADDRESS 에서 앞 뒤로 상관없이 "강원도"가 포함된 모든 공장 조회
SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "%강원도"


-- 예를 들어  ADDRESS 가 
-- "강원도는멀어" ,"눈이오고있는강원도" , "놀러가는장소는강원도입니다" 라면 모두 조회되는것이다.

 

_ 는 문자열의 길이는 지정해 주는것

 

1) 언더바(_) 의 개수는 문자열의 개수를 의미한다.

-- FOOD_FACTORY 테이블의 ADDRESS 에서 앞 두글자는 상관없이 뒤가 "도" 인 경우만 조회
SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "__도" (언더바가 두개임)


-- FOOD_FACTORY 테이블의 ADDRESS 에서 뒤에 한 글자는 상관없이 앞 글자가 "강" 인 경우만 조회
SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "강_" (언더바가 두개임)

또 둘이 같이 쓸 수도 있다.

-- FOOD_FACTORY 테이블의 ADDRESS 에서 "강"으로 시작하고 그 뒤에 글자는 상관없으며 최소 2글자 이상의 데이터만 검색
SELECT FACTORY_ID , FACTORY_NAME , ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE "강_%" (언더바가 두개임)

Lv1. 조건에 부합하는 중고거래 댓글 조회하기

https://school.programmers.co.kr/learn/courses/30/lessons/164673

 

프로그래머스

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

programmers.co.kr

정답

SELECT ub.TITLE , ub.BOARD_ID ,REPLY_ID , ur.WRITER_ID , ur.CONTENTS , DATE_FORMAT(ur.CREATED_DATE , "%Y-%m-%d") AS CREATED_TIME
FROM  USED_GOODS_BOARD ub JOIN USED_GOODS_REPLY ur ON (ub.BOARD_ID = ur.BOARD_ID) 
WHERE DATE_FORMAT(ub.CREATED_DATE , "%Y-%m") = "2022-10" 
ORDER BY ur.CREATED_DATE , ub.TITLE

이 문제는 요구하는 사항이 뭔지 꼼꼼하게 읽어볼 필요가 있다.  WHERE절에서 요구하는 사항은 댓글 작성일이 아닌 게시글작성일 임에 주의하자.


Lv1. 평균 일일 대여 요금 구하기

https://school.programmers.co.kr/learn/courses/30/lessons/151136

 

프로그래머스

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

programmers.co.kr

정답

SELECT ROUND(AVG(DAILY_FEE)) AS AVERAGE_FEE
FROM CAR_RENTAL_COMPANY_CAR
WHERE CAR_TYPE = "SUV"

이 문제에서는 자동차 종류가 'SUV' 인 자동차들의 평균 일일 대여 요금을 출력한다. 이때 일일 대여 요금은 소수 첫 번째 자리에서 반올림해야한다. 그리고 컬럼명은 AVERAGE_FEE 로 출력해야한다.

 

그럼 먼저 평균은 어떻게 구하냐. 집계함수 중 하나인  AVG()를 사용하면된다. 

 

AVG 함수는 컬럼 내 레코드 값의 평균을 구해준다. AVG(DALIY_FEE) 라고 했으니 DALIY_FEE의 평균값이 구해지는 것이다. 

 

다음으로 이 값을 소수 첫 번째 자리에 반올림해야한다. 이때는 ROUND()를 사용한다.

ROUND(숫자,반올림할 자릿수) 인데 반올림할 자릿수에 3을 적었다면 3+1한 자리에서 반올림이 되어 소수 세 번째 자리까지 출력되게 된다. 다음 예시를 살펴보자

SELECT ROUND(4355.1234567) FROM DUAL
-- 4355
 
SELECT ROUND(4355.1234567 ,1) FROM DUAL
-- 4355.1

SELECT ROUND(4355.1234567 ,-1) FROM DUAL
-- 4360
 
SELECT ROUND(4355.1234567 ,-2) FROM DUAL
-- 4400

마지막으로 해당 컬럼명을   AVERAGE_FEE로 바꿔야한다. 이때 AS를 이용하면 된다. AS를 이용하면 속성값을 별칭으로 지정할 수 있다. 

SELECT DALIY_FEE AS FEE
FROM CAR_RENTAL_COMPANY_CAR

--원래는 DALIY_FEE로 출력되지만 AS 로 별칭을 정했기 때문에 FEE로 출력된다.

Lv1. 과일로 만든 아이스크림 고르기

https://school.programmers.co.kr/learn/courses/30/lessons/133025

 

프로그래머스

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

programmers.co.kr

 

정답

SELECT f.FLAVOR 
FROM FIRST_HALF f INNER JOIN ICECREAM_INFO i 
ON f.FLAVOR = i.FLAVOR
WHERE f.TOTAL_ORDER > 3000 AND i.INGREDIENT_TYPE = "fruit_based"
ORDER BY f.TOTAL_ORDER DESC

Lv1. 12세 이하인 여자 환자 목록 출력하기

https://school.programmers.co.kr/learn/courses/30/lessons/132201

 

프로그래머스

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

programmers.co.kr

정답

 

SELECT PT_NAME , PT_NO , GEND_CD , AGE , IFNULL(TLNO , "NONE")
FROM PATIENT 
WHERE AGE <= 12 AND GEND_CD = "W" 
ORDER BY  AGE DESC , PT_NAME

 

이 문제는 전화번호가 없는 경우, "NONE"으로 출력시켜주는 것이 포인트이다.

MySQL 의  IFNULL, CASE, COALESCE를 이용해서 풀어보겠다.

 

 

1) IFNULL

 

해당 컬럼 값이 NULL을 반환할 때, 다른 값으로 출력할 수 있도록 하는 함수이다. (나는 IFNULL을 이용해서 풀었다.)

SELECT IFNULL(TLNO , "NONE")
FROM PATIENT 

-- TLNO 가 NULL 이면 "NONE" 이 출력되고 NULL아니면 TLNO 값이 출력된다.

 

2) CASE 

 

해당 컬럼값을 조건식을 통해 True, False를 판단하여 조건에 맞게  컬럼값을 변환할 때 사용하는 함수

 

기본 구조는 이러하다

CASE 
    WHEN 조건식1 THEN 식1
    WHEN 조건식2 THEN 식2
    ...
    ELSE 조건에 맞는경우가 없는 경우 실행할 식
END
SELECT PT_NAME , PT_NO , GEND_CD , AGE , 
    CASE 
         WHEN TLNO IS NULL THEN "NONE"
        ELSE TLNO
    END AS TLNO
FROM PATIENT 
WHERE AGE <= 12 AND GEND_CD = "W" 
ORDER BY  AGE DESC , PT_NAME

 

3)  COALESCE

 

COALESCE 지정한 표현식들 중에 NULL이 아닌 첫 번째 값을 반환한다.

COALESCE는 배타적 OR 관계 열에서 활용도가 높다.

 

예를 들자면 이렇다

SELECT COALESCE(Column1, Column2, Column3, Column4)
FROM PATIENT

--  Column1 ~ 4 중에 처음으로 만나는 NULL이 아닌 값을 출력한다.
-- Column1,3,4가 NUL이 아니고 Column2가 NULL이였다면 Column 2가 출력되는것이다.
SELECT PT_NAME , PT_NO , GEND_CD , AGE ,  COALESCE (TLNO, 'NONE')
FROM PATIENT 
WHERE AGE <= 12 AND GEND_CD = "W" 
ORDER BY  AGE DESC , PT_NAME

 


Lv2. 3월에 태어난 여성 회원 목록 출력하기

https://school.programmers.co.kr/learn/courses/30/lessons/131120

 

프로그래머스

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

programmers.co.kr

정답

SELECT MEMBER_ID ,  MEMBER_NAME , GENDER ,DATE_FORMAT(DATE_OF_BIRTH, "%Y-%m-%d") AS DATE_OF_BIRTH 
FROM MEMBER_PROFILE 
WHERE GENDER = "W" AND DATE_FORMAT(DATE_OF_BIRTH, "%m") = "03" AND TLNO IS NOT NULL
ORDER BY MEMBER_ID

이 문제는 전화번호가 NULL인 경우는 제외시켜 출력해야한다. 해당 컬럼이  NULL이 아닌경우를 검색하기 위하여 IS NOT NULL을 이용하면된다.


Lv2. 재구매가 일어난  상품과 회원 리스트 구하기

https://school.programmers.co.kr/learn/courses/30/lessons/131536

 

프로그래머스

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

programmers.co.kr

정답

SELECT USER_ID , PRODUCT_ID
FROM ONLINE_SALE 
GROUP BY USER_ID , PRODUCT_ID
HAVING COUNT(*) > 1
ORDER BY USER_ID , PRODUCT_ID DESC

GROUP BY와 HAVING 절을 적절히 사용

 


Lv4. 서울에 위치한 식당 목록 출력하기

https://school.programmers.co.kr/learn/courses/30/lessons/131118

 

프로그래머스

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

programmers.co.kr

풀이

SELECT ri.REST_ID , ri.REST_NAME , ri.FOOD_TYPE , ri.FAVORITES , ri.ADDRESS , ROUND(AVG(rr.REVIEW_SCORE) , 2) AS REVIEW_SCORE
FROM REST_INFO ri INNER JOIN REST_REVIEW rr
ON ri.REST_ID = rr.REST_ID
WHERE ri.ADDRESS LIKE "서울%"
GROUP BY ri.REST_ID
ORDER BY REVIEW_SCORE DESC , ri.FAVORITES DESC

Lv4. 오프라인/온라인 판매 데이터 통합하기

https://school.programmers.co.kr/learn/courses/30/lessons/131537

 

프로그래머스

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

programmers.co.kr

풀이

SELECT  DATE_FORMAT(SALES_DATE,"%Y-%m-%d") , PRODUCT_ID , USER_ID ,SALES_AMOUNT
FROM ONLINE_SALE
WHERE DATE_FORMAT(SALES_DATE,"%Y-%m") = "2022-03" 
UNION ALL
SELECT DATE_FORMAT(SALES_DATE,"%Y-%m-%d") , PRODUCT_ID , NULL AS USER_ID ,SALES_AMOUNT
FROM OFFLINE_SALE
WHERE DATE_FORMAT(SALES_DATE,"%Y-%m") = "2022-03" 
ORDER BY 1,2,3