2024. 9. 17. 17:17ㆍ코딩 테스트(Coding Test)/프로그래머스
평균 일일 대여 요금 구하기
나의 답)
SELECT ROUND(AVG(DAILY_FEE), 0) AS AVERAGE_FEE
FROM CAR_RENTAL_COMPANY_CAR
WHERE CAR_TYPE = 'SUV';
# CAR_RENTAL_COMPANY_CAR 테이블에서
# 자동차 종류가 'SUV'인 자동차들의
# 평균 일일 대여 요금 출력 -> 소수 첫 번째 자리에서 반올림 & 컬럼명은 AVERAGE_FEE
흉부외과 또는 일반외과 의사 목록 출력하기
나의 답)
SELECT DR_NAME, DR_ID, MCDP_CD, DATE_FORMAT(HIRE_YMD, "%Y-%m-%d") AS HIRE_YMD
FROM DOCTOR
WHERE MCDP_CD = 'CS' || MCDP_CD = 'GS'
ORDER BY HIRE_YMD DESC, DR_NAME ASC;
# DOCTOR 테이블에서
# 진료과가 흉부외과(CS) || 일반외과(GS)인 의사의
# 이름, 의사ID, 진료과, 고용일자 조회
# 고용일자를 기준으로 내림차순, 이름을 기준으로 오름차순
과일로 만든 아이스크림 고르기
나의 답)
SELECT fh.FLAVOR
FROM FIRST_HALF fh
INNER JOIN ICECREAM_INFO ii
ON fh.FLAVOR = ii.FLAVOR
WHERE TOTAL_ORDER > 3000 AND ii.INGREDIENT_TYPE = 'fruit_based'
ORDER BY TOTAL_ORDER DESC;
# 상반기 아이스크림의
# 총주문량 > 3,000 && 주성분 == '과일'인 아이스크림 맛을
# 총주문량 DESC
3월에 태어난 여성 회원 목록 출력하기
나의 답)
SELECT MEMBER_ID, MEMBER_NAME, GENDER, DATE_FORMAT(DATE_OF_BIRTH, "%Y-%m-%d") AS DATE_OF_BIRTH
FROM MEMBER_PROFILE
WHERE MONTH(DATE_OF_BIRTH) = 3 AND GENDER = 'W' AND TLNO IS NOT NULL
ORDER BY MEMBER_ID ASC;
# MEMBER_PROFILE 테이블에서
# 생일이 '3월'인 '여성'회원의
# ID, 이름, 성별, 생년월인 조회
# if) 전화번호 == NULL 출력x
# 회원ID 기준 ASC
# 날짜 출력형식 확인
서울에 위치한 식당 목록 출력하기
나의 답1)
SELECT ri.REST_ID, ri.REST_NAME, ri.FOOD_TYPE, ri.FAVORITES, ri.ADDRESS, ROUND(AVG(rr.REVIEW_SCORE), 2) AS SCORE
FROM REST_INFO ri, REST_REVIEW rr
WHERE ADDRESS LIKE '서울%' AND ri.REST_ID = rr.REST_ID
GROUP BY ri.REST_ID, ri.REST_NAME, ri.FOOD_TYPE, ri.FAVORITES, ri.ADDRESS
ORDER BY SCORE DESC, FAVORITES DESC;
# REST_INFO, REST_REVIEW 테이블에서
# '서울'에 위치한 식당들의
# 식당ID, 식당 이름, 음식 종류, 즐겨찾기수, 주소, 리뷰 평균 점수 조회
# 리뷰 평균 점수 -> 소수점 세 번째 자리에서 반올림
# 평균점수 DESC, 즐겨찾기수 DESC
평균을 내기 때문에 GROUP BY를 사용하여 나머지 요소들을 묶어줌
나의 답2)
SELECT ri.REST_ID, ri.REST_NAME, ri.FOOD_TYPE, ri.FAVORITES, ri.ADDRESS, ROUND(AVG(rr.REVIEW_SCORE), 2) AS SCORE
FROM REST_INFO ri
JOIN REST_REVIEW rr
ON ri.REST_ID = rr.REST_ID
WHERE ADDRESS LIKE '서울%'
GROUP BY ri.REST_ID, ri.REST_NAME, ri.FOOD_TYPE, ri.FAVORITES, ri.ADDRESS
ORDER BY SCORE DESC, FAVORITES DESC;
# REST_INFO, REST_REVIEW 테이블에서
# '서울'에 위치한 식당들의
# 식당ID, 식당 이름, 음식 종류, 즐겨찾기수, 주소, 리뷰 평균 점수 조회
# 리뷰 평균 점수 -> 소수점 세 번째 자리에서 반올림
# 평균점수 DESC, 즐겨찾기수 DESC
평균을 내기 때문에 GROUP BY를 사용하여 나머지 요소들을 묶어줌
조건에 부합하는 중고거래 댓글 조회하기
나의 답1)
SELECT ugb.TITLE, ugb.BOARD_ID, ugr.REPLY_ID, ugr.WRITER_ID, ugr.CONTENTS, DATE_FORMAT(ugr.CREATED_DATE, '%Y-%m-%d') AS CREATED_DATE
FROM USED_GOODS_BOARD ugb, USED_GOODS_REPLY ugr
WHERE DATE_FORMAT(ugb.CREATED_DATE, '%Y-%m') = '2022-10' AND ugb.BOARD_ID = ugr.BOARD_ID
ORDER BY CREATED_DATE ASC, ugb.TITLE ASC;
# USED_GOODS_BOARD, USED_GOODS_REPLY에서
# 2022년 10월에 작성된
# 게시글 제목, 게시글 ID, 댓글 ID, 댓글 작성자 ID, 댓글 내용, 댓글 작성일 조회
# 댓글 작성일 ASC, 게시글 제목 ASC
나의 답2)
SELECT ugb.TITLE, ugb.BOARD_ID, ugr.REPLY_ID, ugr.WRITER_ID, ugr.CONTENTS, DATE_FORMAT(ugr.CREATED_DATE, '%Y-%m-%d') AS CREATED_DATE
FROM USED_GOODS_BOARD ugb
JOIN USED_GOODS_REPLY ugr
ON ugb.BOARD_ID = ugr.BOARD_ID
WHERE DATE_FORMAT(ugb.CREATED_DATE, '%Y-%m') = '2022-10'
ORDER BY CREATED_DATE ASC, ugb.TITLE ASC;
# USED_GOODS_BOARD, USED_GOODS_REPLY에서
# 2022년 10월에 작성된
# 게시글 제목, 게시글 ID, 댓글 ID, 댓글 작성자 ID, 댓글 내용, 댓글 작성일 조회
# 댓글 작성일 ASC, 게시글 제목 ASC
인기있는 아이스크림
나의 답)
SELECT FLAVOR
FROM FIRST_HALF
ORDER BY TOTAL_ORDER DESC, SHIPMENT_ID ASC;
# FIRST_HALF에서
# 아이스크림의 맛을
# 총주문량 DESC, 출하 번호 ASC
강원도에 위치한 생상공장 목록 출력하기
나의 답)
SELECT FACTORY_ID, FACTORY_NAME, ADDRESS
FROM FOOD_FACTORY
WHERE ADDRESS LIKE '강원도%'
ORDER BY FACTORY_ID ASC;
# FOOD_FACTORY에서
# '강원도'에 위치한
# 공장 ID, 공장 이름, 주소 조회
# 공장 ID ASC
12세 이하인 여자 환자 목록 출력하기
나의 답)
SELECT PT_NAME, PT_NO, GEND_CD, AGE, IFNULL(TLNO, 'NONE') AS TLNO
FROM PATIENT
WHERE AGE <= 12 AND GEND_CD = 'W'
ORDER BY AGE DESC, PT_NAME ASC;
# PATIENT에서
# '12세 이하'인 '여자'환자의
# 환자이름, 환자번호, 성별코드, 나이, 전화번호 조회
# if) 전화번호 == NULL -> 'NONE'으로 출력
# 나이 DESC, 환자이름 ASC
조건에 맞는 도서 리스트 출력하기
나의 답)
SELECT BOOK_ID, DATE_FORMAT(PUBLISHED_DATE, '%Y-%m-%d') AS PUBLISHED_DATE
FROM BOOK
WHERE DATE_FORMAT(PUBLISHED_DATE, '%Y') = '2021' AND CATEGORY = '인문'
ORDER BY PUBLISHED_DATE ASC;
# BOOK에서
# '2021'년에 출판된 '인문'카테고리에 속하는
# 도서 ID, 출판일 출력
# 출판일 ASC
재구매가 일어난 상품과 회원 리스트 구하기
나의 답)
SELECT USER_ID, PRODUCT_ID
FROM ONLINE_SALE
GROUP BY USER_ID, PRODUCT_ID
HAVING COUNT(*) >= 2
ORDER BY USER_ID ASC, PRODUCT_ID DESC;
# ONLINE_SALE에서
# 동일한 회원이 동일한 상품을 재구매한 데이터를 구하여
# 재구매한 회원 ID, 재구매한 상품 ID 출력
# 회원 ID ASC, 상품 ID DESC
모든 레코드 조회하기
나의 답)
SELECT *
FROM ANIMAL_INS
ORDER BY ANIMAL_ID ASC;
# ANIMAL_INS에서
# *를
# ANIMAL_ID ASC;
역순 정렬하기
나의 답)
SELECT NAME, DATETIME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC;
# ANIMAL_INS에서
# 동물의 이름, 보호 시작일 조회
# ANIMAL_ID DESC
오프라인/온라인 판매 데이터 통합하기
나의 답)
SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d') AS SALES_DATE, 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') AS SALES_DATE, PRODUCT_ID, NULL AS USER_ID, SALES_AMOUNT
FROM OFFLINE_SALE
WHERE DATE_FORMAT(SALES_DATE, '%Y-%m') = '2022-03'
ORDER BY SALES_DATE ASC, PRODUCT_ID, USER_ID ASC;
# ONLINE_SALE, OFFLINE_SALE에서
# '2022-03'의 오프라인/온라인 상품 판매 데이터의
# 판매 날짜, 상품ID, 유저ID, 판매량 출력
# OFFLINE_SALE의 USER_ID는 'NULL'로 표시
# 판매일 ASC, 상품ID ASC, 유저ID ASC
아픈 동물 찾기
나의 답)
SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
WHERE INTAKE_CONDITION = 'Sick'
ORDER BY ANIMAL_ID ASC;
# ANIMAL_INS에서
# '아픈' 동물의
# 아이디, 이름 조회
# 아이디 ASC
동물의 아이디와 이름
나의 답)
SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID ASC;
# ANIMAL_INS에서
# 모든 동물의 아이디, 이름 조회
# ANIMAL_ID ASC
여러 기준으로 정렬하기
나의 답)
SELECT ANIMAL_ID, NAME, DATETIME
FROM ANIMAL_INS
ORDER BY NAME ASC, DATETIME DESC;
# ANIMAL_INS에서
# 아이디, 이름, 보호 시작일 조회
# 이름 ASC, 보호 시작일 DESC
상위 n개 레코드
나의 답)
SELECT NAME
FROM ANIMAL_INS
ORDER BY DATETIME ASC
LIMIT 1;
# ANIMAL_INS에서
# LIMIT 1
# 이름
# 보호 시작일 ASC
조건에 맞는 회원 수 구하기
나의 답)
SELECT COUNT(*)
FROM USER_INFO
WHERE DATE_FORMAT(JOINED, '%Y') = 2021 AND AGE >= 20 AND AGE <= 29;
# USER_INFO에서
# '2021'년에 가입한 회원 중
# 나이 >= 20 && 나이 <= 29인 회원이
# 몇 명인지 출력
업그레이드 된 아이템 구하기
나의 답)
SELECT ii.ITEM_ID, ii.ITEM_NAME, ii.RARITY
FROM ITEM_INFO ii
JOIN ITEM_TREE it
ON ii.ITEM_ID = it.ITEM_ID
WHERE it.PARENT_ITEM_ID IN (SELECT ITEM_ID FROM ITEM_INFO WHERE RARITY = 'RARE')
ORDER BY ii.ITEM_ID DESC;
# ITEM_INFO, ITEM_TREE에서
# 아이템의 희귀도가 'RARE'인 아이템의
# 다음 업그레이드 아이템의
# 아이템ID, 아이템 명, 아이템의 희귀도 출력
# 아이템ID DESC
나의 답2)
SELECT ii2.ITEM_ID, ii2.ITEM_NAME, ii2.RARITY
FROM ITEM_INFO ii
JOIN ITEM_TREE it
ON ii.ITEM_ID = it.PARENT_ITEM_ID
JOIN ITEM_INFO ii2
ON it.ITEM_ID = ii2.ITEM_ID
WHERE ii.RARITY = 'RARE'
ORDER BY ii2.ITEM_ID DESC;
# ITEM_INFO, ITEM_TREE에서
# 아이템의 희귀도가 'RARE'인 아이템의
# 다음 업그레이드 아이템의
# 아이템ID, 아이템 명, 아이템의 희귀도 출력
# 아이템ID DESC
Python 개발자 찾기
나의 답)
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPER_INFOS
WHERE SKILL_1 = 'Python' || SKILL_2 = 'Python' || SKILL_3 = 'Python'
ORDER BY ID ASC;
# DEVELOPER_INFOS에서
# 'Python' 스킬을 가진 개발자의
# ID, 이메일, 이름, 성 조회
# ID ASC
조건에 맞는 개발자 찾기
나의 답1)
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS d
WHERE SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'Python')
OR SKILL_CODE & (SELECT CODE FROM SKILLCODES WHERE NAME = 'C#')
ORDER BY ID ASC;
# SKILLCODES, DEVELOPERS에서
# 'Python' || 'C#'스킬을 가진 개발자의
# ID, 이메일, 이름, 성 조회
# ID ASC
나의 답2)
SELECT ID, EMAIL, FIRST_NAME, LAST_NAME
FROM DEVELOPERS d
JOIN SKILLCODES s
ON (d.SKILL_CODE & s.CODE) != 0
WHERE s.NAME = 'Python' OR s.NAME = 'C#'
ORDER BY ID ASC;
# SKILLCODES, DEVELOPERS에서
# 'Python' || 'C#'스킬을 가진 개발자의
# ID, 이메일, 이름, 성 조회
# ID ASC
비트 연산을 하여 Python 혹은 C#이 있는지 확인함
잔챙이 잡은 수 구하기
나의 답)
SELECT COUNT(*) AS FISH_COUNT
FROM FISH_INFO
WHERE LENGTH IS NULL;
# FISH_INFO에서
# 길이가 <= 10인
# 물고기의 수 출력 -> FISH_COUNT
가장 큰 물고기 10마리 구하기
나의 답)
SELECT ID, LENGTH
FROM FISH_INFO
ORDER BY LENGTH DESC, ID ASC
LIMIT 10;
# FISH_INFO에서
# 가장 큰 물고기 10마리의
# ID, 길이 출력
# 길이 DESC, ID ASC
특정 물고기를 잡은 총 수 구하기
나의 답1)
SELECT COUNT(*) AS FISH_COUNT
FROM FISH_INFO fi, FISH_NAME_INFO fni
WHERE fi.FISH_TYPE = fni.FISH_TYPE AND FISH_NAME IN ('BASS', 'SNAPPER');
# FISH_INFO, FISH_NAME_INFO에서
# BASS, SNAPPER의 수 출력 -> FISH_COUNT
나의 답2)
SELECT COUNT(*) AS FISH_COUNT
FROM FISH_INFO fi
JOIN FISH_NAME_INFO fni
ON fi.FISH_TYPE = fni.FISH_TYPE
WHERE FISH_NAME = 'BASS' OR FISH_NAME = 'SNAPPER';
# FISH_INFO, FISH_NAME_INFO에서
# BASS, SNAPPER의 수 출력 -> FISH_COUNT
대장균들의 자식의 수 구하기
SELECT ed.ID, IFNULL(COUNT(ed1.ID), 0) AS CHILD_COUNT
FROM ECOLI_DATA ed
LEFT JOIN ECOLI_DATA ed1
ON ed.ID = ed1.PARENT_ID
GROUP BY ed.ID
ORDER BY ed.ID ASC;
# ECOLI_DATA에서
# ID, 자식의 수 출력
# if) 자식의 수 == NULL -> 0으로 출력
# ID ASC
대장균의 크기에 따라 분류하기1
나의 답)
SELECT ID, CASE WHEN SIZE_OF_COLONY <= 100 THEN 'LOW' WHEN SIZE_OF_COLONY <= 1000 THEN 'MEDIUM' ELSE 'HIGH' END AS SIZE
FROM ECOLI_DATA
ORDER BY ID ASC;
# ECOLI_DATA에서
# ID, SIZE 출력
# ID ASC;
특정 형질을 가지는 대장균 찾기
나의 답)
SELECT COUNT(*) AS COUNT
FROM ECOLI_DATA
WHERE (GENOTYPE & 2) = 0 -- 2번 형질을 보유하지 않음
AND ((GENOTYPE & 1) = 1 OR (GENOTYPE & 4) = 4) -- 1번 형질 또는 3번 형질을 보유
부모의 형질을 모두 가지는 대장균 찾기
나의 답)
SELECT ed.ID, ed.GENOTYPE, ed1.GENOTYPE AS PARENT_GENOTYPE
FROM ECOLI_DATA ed
JOIN ECOLI_DATA ed1
ON ed.PARENT_ID = ed1.ID
WHERE (ed.GENOTYPE & ed1.GENOTYPE) = ed1.GENOTYPE
ORDER BY ed.ID ASC;
# ECOLI_DATA에서
# 부모의 형질을 모두 보유한 대장균의
# ID, 형질, 부모 대장균의 형질 출력
# ID ASC
대장균의 크기에 따라 분류하기2
나의 답1)
WITH Ranked_Ecoli AS (
SELECT
ID,
SIZE_OF_COLONY,
NTILE(4) OVER (ORDER BY SIZE_OF_COLONY DESC) AS tile_rank
FROM ECOLI_DATA
)
SELECT
ID,
CASE
WHEN tile_rank = 1 THEN 'CRITICAL'
WHEN tile_rank = 2 THEN 'HIGH'
WHEN tile_rank = 3 THEN 'MEDIUM'
ELSE 'LOW'
END AS COLONY_NAME
FROM Ranked_Ecoli
ORDER BY ID ASC;
# ECOLI_DATA에서
# ID, 분류된 이름(COLONY_NAME) 출력
# ID ASC
* NTILE(): 데이터를 지정한 숫자만큼 균등하게 나누는 역할을 한다.
* OVER: 함수가 적용될 데이터 범위를 정의한다.
나의 답2)
WITH Ranked_Ecoli AS (
SELECT
ID,
SIZE_OF_COLONY,
PERCENT_RANK() OVER (ORDER BY SIZE_OF_COLONY DESC) AS pct_rank
FROM ECOLI_DATA
)
SELECT
ID,
CASE
WHEN pct_rank <= 0.25 THEN 'CRITICAL'
WHEN pct_rank <= 0.50 THEN 'HIGH'
WHEN pct_rank <= 0.75 THEN 'MEDIUM'
ELSE 'LOW'
END AS COLONY_NAME
FROM Ranked_Ecoli
ORDER BY ID ASC;
# ECOLI_DATA에서
# ID, 분류된 이름(COLONY_NAME) 출력
# ID ASC
* PERCENT_RANK(): 각 값이 전체 집합에서 얼마나 상위에 있는지 백분율로 나타낸다.
나의 답3)
WITH Ranked_Ecoli AS (
SELECT
ID,
SIZE_OF_COLONY,
ROW_NUMBER() OVER (ORDER BY SIZE_OF_COLONY DESC) AS rn,
COUNT(*) OVER () AS total_count
FROM ECOLI_DATA
)
SELECT
ID,
CASE
WHEN rn <= total_count / 4 THEN 'CRITICAL'
WHEN rn <= total_count / 2 THEN 'HIGH'
WHEN rn <= total_count * 3 / 4 THEN 'MEDIUM'
ELSE 'LOW'
END AS COLONY_NAME
FROM Ranked_Ecoli
ORDER BY ID ASC;
# ECOLI_DATA에서
# ID, 분류된 이름(COLONY_NAME) 출력
# ID ASC
* ROW_NUMBER(): 각 개체에 고유한 순번을 부여한다. 가장 큰 대장균이 1번, 그다음 대장균이 2번이 된다.
* COUNT(*) OVER () AS total_count: 대장균 개체의 총 개수를 total_count라는 별칭으로 저장한다.
특정 세대의 대장균 찾기
나의 답)
SELECT e3.ID
FROM ECOLI_DATA e1
JOIN ECOLI_DATA e2 ON e2.PARENT_ID = e1.ID
JOIN ECOLI_DATA e3 ON e3.PARENT_ID = e2.ID
WHERE e1.PARENT_ID IS NULL
ORDER BY e3.ID ASC;
# ECOLI_DATA에서
# '3세대' 대장균의
# ID 출력
# ID ASC;
멸종위기의 대장균 찾기
나의 답)
WITH RECURSIVE GENERATION_CTE AS (
-- 최초의 1세대 부모를 찾습니다 (PARENT_ID가 NULL인 개체들)
SELECT ID, 1 AS GENERATION
FROM ECOLI_DATA
WHERE PARENT_ID IS NULL
UNION ALL
-- 각 부모의 자식들에 대해 세대를 하나씩 증가시켜 연결합니다.
SELECT E.ID, G.GENERATION + 1
FROM ECOLI_DATA E
JOIN GENERATION_CTE G ON E.PARENT_ID = G.ID
)
-- 이제 자식이 없는 개체들을 찾습니다.
SELECT COUNT(*) AS COUNT, GENERATION
FROM GENERATION_CTE G
LEFT JOIN ECOLI_DATA E ON G.ID = E.PARENT_ID
WHERE E.ID IS NULL -- 자식이 없는 개체들
GROUP BY GENERATION
ORDER BY GENERATION ASC;
# ECOLI_DATA에서
# 자식이 없는
# 개체의 수(COUNT), 세대(GENERATION) 출력
# 세대 ASC;
[해결 과정]
1. 각 세대(GENERATION)을 구분하기 위해 PARENT_ID와 ID의 관계를 기반으로 트리를 구성한다.
2. 자식이 없는 대장균을 찾아야 하므로, 각 개체가 다른 개체의 PARENT_ID로 사용되지 않는 경우를 찾아야 한다.
3. 세대를 정의하기 위해, 최초의 부모(PARENT_ID가 NULL인 개체들)가 1세대이고, 그들의 자식들이 2세대, 그 자식들이 3세대... 이런 식으로 세대 관계를 구성할 수 있다.
'코딩 테스트(Coding Test) > 프로그래머스' 카테고리의 다른 글
[프로그래머스/SQL 고득점 Kit] IS NULL (1) | 2024.09.17 |
---|---|
[프로그래머스/SQL 고득점 Kit] SUM, MAX, MIN (0) | 2024.09.17 |
[java] 프로그래머스 문자열 반복해서 출력하기 / .repeat() (0) | 2024.04.10 |
[프로그래머스/js] 직각삼각형 출력하기 (0) | 2023.04.03 |
[프로그래머스/js] 짝수의 합 (0) | 2023.04.02 |