SELECT
Lv1.조건에 맞는 회원 수 구하기
https://school.programmers.co.kr/learn/courses/30/lessons/131535
풀이
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
정답
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
정답
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
정답
SELECT ANIMAL_ID, NAME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID
Lv1. 어린 동물 찾기
https://school.programmers.co.kr/learn/courses/30/lessons/59037
정답
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
정답
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
정답
SELECT NAME , DATETIME
FROM ANIMAL_INS
ORDER BY ANIMAL_ID DESC
Lv1. 조건에 맞는 도서 리스트 출력하기
https://school.programmers.co.kr/learn/courses/30/lessons/144853
정답
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
%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
정답
SELECT FLAVOR
FROM FIRST_HALF
ORDER BY TOTAL_ORDER DESC , SHIPMENT_ID
Lv1. 흉부외과 또는 일반외과 의사 목록 출력하기
https://school.programmers.co.kr/learn/courses/30/lessons/132203
정답
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
정답
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
정답
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
정답
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
정답
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
정답
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
정답
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
정답
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
풀이
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
풀이
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
'SQL' 카테고리의 다른 글
Having에 Select의 Alias(별칭)을 쓸 수 있다니.. (0) | 2023.06.20 |
---|---|
프로그래머스 SQL 고득점 Kit 풀이 - JOIN 편 (0) | 2023.05.26 |
프로그래머스 SQL 고득점 Kit - IS NULL 편 (0) | 2023.05.19 |
프로그래머스 SQL 고득점 Kit 풀이 - SUM, MAX, MIN 편 (0) | 2023.05.11 |