2024-02-20
오늘은 프로그래머스 SQL 킷의 SUM, MAX, MIN 그리고 GROUP BY를 풀 것.
업랜디도 한판 하겠다.
공부 계획
- 2월 20일 - SUM, MAX, MIN | GROUP BY 풀이 ✅ 2024-02-20
- 2월 21일 - IS NULL | JOIN 풀이
- 2월 22일 - String, Date 풀고 SQL 복습 및 PS 복습
- 2월 23일 - 최종 복습 및 컨디션 관리
오늘의 업랜디
26070 곰곰이와 학식 (해결 - 구현, 그리디, 시뮬레이션)
- 프로그래머스 SQL 고득점 Kit
- SELECT ✅ 2024-02-19
- SUM, MAX, MIN ✅ 2024-02-20
- GROUP BY
- IS NULL
- JOIN
- String, Date
- ⏬ 삼중 조인, 서브 쿼리, 함수, 자연 조인
곰곰이와 학식
치킨을 먹고 싶은 곰곰이 수 A, 피자를 먹고 싶은 곰곰이 수 B, 햄버거를 먹고 싶은 곰곰이 수 C가 있다.
총총선배가 갖고 있는 학식권의 수 X, Y, Z가 주어질 때 먹일 수 있는 곰곰이의 수를 구하는 문제다.
특이한 것은, 식당에서 치킨 식권 3장을 피자 식권 1장으로, 피자 식권 3장을 햄버거 식권 1장으로, 햄버거 식권 3장을 치킨 식권 1장으로 교환해주는 이벤트를 하고있다.
그저 단순 시뮬레이션 + 구현 문제인데, 그리디적 요소가 포함되어 있었다. 먼저 현재 갖고 있는 식권을 모두 소비하고, 다음 교환가능한 식권으로 계속 불가능할때까지 바꾸면서 최대한 많은 곰곰이를 먹이도록 구현했다.
치킨 -> 피자 -> 햄버거 순으로 교환이되는데, 문제를 서로 모든 종류의 음식에 대해 교환되는 줄 알고 잘못 이해해서 시간이 좀 걸렸다.
// 백준: 곰곰이와 학식
// https://www.acmicpc.net/problem/26070
// 2024-02-20
#include <algorithm>
#include <iostream>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
long long A, B, C, X, Y, Z;
cin >> A >> B >> C;
cin >> X >> Y >> Z;
long long fed = 0;
// 식권 바로 사용
long long minChicken = min(A, X);
A -= minChicken;
X -= minChicken;
fed += minChicken;
long long minPizza = min(B, Y);
B -= minPizza;
Y -= minPizza;
fed += minPizza;
long long minBurger = min(C, Z);
C -= minBurger;
Z -= minBurger;
fed += minBurger;
while (true) {
bool exchanged = false;
// 치킨 식권을 피자 식권으로 교환
while (X >= 3) {
X -= 3;
// B--;
Y++;
// fed++;
exchanged = true;
}
// 피자 식권 사용
while (Y > 0 && B > 0) {
Y--;
B--;
fed++;
exchanged = true;
}
// 피자 식권을 햄버거 식권으로 교환
while (Y >= 3) {
Y -= 3;
// C--;
Z++;
// fed++;
exchanged = true;
}
// 햄버거 식권 사용
while (Z > 0 && C > 0) {
Z--;
C--;
fed++;
exchanged = true;
}
// 햄버거 식권을 치킨 식권으로 교환
while (Z >= 3) {
Z -= 3;
// A--;
X++;
// fed++;
exchanged = true;
}
// 치킨 식권 사용
while (X > 0 && A > 0) {
X--;
A--;
fed++;
exchanged = true;
}
if (!exchanged)
break;
}
cout << fed;
return 0;
}
프로그래머스 SQL
- 오늘의 SQL 문제 해결: 23문제
SQL에서의 비교 (IS, =)
SQL에서 IS 문은 NULL값을 비교할 때 쓰인다.
A != NULL로 하면 알 수 없는 값과 비교를 하는 것이기 때문에, 결과도 알 수 없음으로 평가된다.
따라서, NULL값을 비교할 때는 A IS NOT NULL로 해야한다.
= 은 존재하는 두 값을 비교할때에 쓰인다.
--이름이 NULL인 경우는 집계하지 않으며 중복되는 이름은 하나로 칩니다...
SELECT COUNT(DISTINCT NAME) AS count
FROM ANIMAL_INS
WHERE NAME IS NOT NULL;
SUM과 COUNT
SQL에서 SUM은 숫자 데이터를 다루는 열에 대해, 합계 값을 얻을 때 쓴다.
COUNT는 해당 컬럼의 개수를 센다.
--동물 보호소에 동물이 몇 마리 들어왔는지 조회하는 SQL 문을 작성해주세요.
SELECT COUNT(ANIMAL_ID) AS count
FROM ANIMAL_INS;
--테이블에서 희귀도가 'LEGEND'인 아이템들의 가격의 총합을 구하는 SQL문
SELECT SUM(PRICE) AS TOTAL_PRICE
FROM ITEM_INFO
WHERE RARITY = 'LEGEND'
CASE, WHEN, THEN, ELSE, END
테이블에서 2022년 10월 16일에 대여 중인 자동차인 경우 '대여중' 이라고 표시하고, 대여 중이지 않은 자동차인 경우 '대여 가능'을 표시하는 컬럼(컬럼명: AVAILABILITY)을 추가하여 자동차 ID와 AVAILABILITY 리스트를 출력하는 SQL문을 작성해주세요.
SELECT
CAR_ID,
MAX(
CASE WHEN
'2022-10-16' BETWEEN START_DATE AND END_DATE
THEN '대여중'
ELSE '대여 가능'
END
) AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
ORDER BY 1 DESC
GROUP BY로 CAR_ID로 묶을 때, 대여중과 대여 가능 두가지 상태가 겹칠 수 있는데. 이때 항상 대여중을 고르기 위해 MAX를 사용한다.
CASE WHEN (조건) THEN (TRUE면) ELSE (FALSE면) END.
로 SQL에서 IF문을 사용할 수 있다.
SELECT
CAR_ID,
IF(
COUNT(IF('2022-10-16' BETWEEN DATE_FORMAT(START_DATE, '%Y-%m-%d') AND DATE_FORMAT(END_DATE, '%Y-%m-%d'), 1, NULL)) > 0,
'대여중',
'대여 가능'
) AS AVAILABILITY
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY CAR_ID
ORDER BY CAR_ID DESC
위에서 사용된 IF문은 시작 기간과 종료 기간 사이에 2022-10-16이 있다면 1을 반환하고, 아니라면 NULL을 반환 하는데, 실질적으로 COUNT는 NULL이 아닌 값은 세지 않기 때문에. 이걸 다시 IF로 감싸고, COUNT 반환 값이 0 초과인지 확인하고. 초과라면 '대여중' 아니라면 '대여 가능' 으로 AS AVAILABILITY에 추가한다.
와 !!
어렵다.
- 다시 메모
GROUP BY 는 집계 함수를 특정 기준으로 묶는데에 쓰인다.
SELECT
A.AUTHOR_ID, A.AUTHOR_NAME, B.CATEGORY, SUM(B.PRICE * S.SALES) AS TOTAL_SALES
FROM
BOOK B
INNER JOIN AUTHOR A ON B.AUTHOR_ID = A.AUTHOR_ID
INNER JOIN BOOK_SALES S ON S.BOOK_ID = B.BOOK_ID
WHERE
S.SALES_DATE BETWEEN '2022-01-01' AND '2022-01-31'
GROUP BY A.AUTHOR_ID, B.CATEGORY
ORDER BY A.AUTHOR_ID ASC, B.CATEGORY DESC;
IN 연산자
IN 연산자는 주어진 값 목록에서 하나라도 일치하는 값을 가진 행을 선택하는데에 사용된다.
SELECT column_names
FROM table_name
WHERE column_name IN (value1, value2, ..., valueN);
재귀 RECURSIVE
SQL에서도 재귀를 사용할 수 있다. 예를 들어서 0부터 23까지의 시간 테이블을 만들고, 그 테이블에 데이터를 삽입하고 싶을 때, 시간 테이블을 만드는데에 아래와 같이 재귀를 활용할 수 있다.
WITH RECURSIVE NumberSequence AS (
SELECT 1 AS Number -- 기본 케이스
UNION ALL
SELECT Number + 1 FROM NumberSequence WHERE Number < 10 -- 재귀적 부분
)
SELECT * FROM NumberSequence;
왼쪽 조인 (LEFT JOIN)
바로 위에서 설명한 것과 같이, 만든 시간 테이블에 데이터를 삽입하고 싶을 때 왼쪽 조인을 쓸 수 있다.
INNER JOIN은 데이터가 겹치는 부분만 남기지만, 왼쪽 조인은 "기준 테이블"(왼쪽 테이블)의 모든 행과, 그 행과 일치하는 "조인 테이블"(오른쪽 테이블)의 행을 반환한다. 만약 조인 테이블에서 일치하는 행이 없다면, 해당 필드는 NULL
로 채워진다.

WITH RECURSIVE HOURS AS (
SELECT 0 AS HOUR
UNION ALL
SELECT HOUR + 1 FROM HOURS WHERE HOUR < 23
)
SELECT
H.HOUR,
COALESCE(COUNT(A.ANIMAL_ID), 0) AS COUNT
FROM
HOURS H
LEFT JOIN
ANIMAL_OUTS A ON HOUR(A.DATETIME) = H.HOUR
GROUP BY
H.HOUR
EXTRACT
EXTRACT는 시간 값, 날짜 값으로부터 특정 부분 (년,월,일,시,분,초 등)을 추출할 수 있는 함수다.
EXTRACT(field FROM source)
field: 예를 들어 YEAR, MONTH, DAY, HOUR, MINUTE
source: 날짜, 시간 값을 포함하는 컬럼 또는 표현식.
-- 예시
LEFT JOIN
ANIMAL_OUTS AO ON TH.HOUR = EXTRACT(HOUR FROM AO.DATETIME)
FLOOR() 함수의 예시
예를 들어서 PRODUCT
테이블에서 만원 단위의 가격대 별로 상품 개수를 출력하고 싶을 때 FLOOR() 함수를 쓸 수 있다. 가격/10000의 값을 내림 처리하고, 다시 곱하기 10000을 하면 된다 !!
SELECT
FLOOR(PRICE / 10000) * 10000 AS PRICE_GROUP,
COUNT(*) AS PRODUCTS
FROM
PRODUCT
GROUP BY
PRICE_GROUP
ORDER BY PRICE ASC;
오늘은 이렇게 오늘의 목표 학습이었던,
프로그래머스 SQL : SUM, MAX, MIN | GROUP BY 파트의 23문제를 완료했다.
GROUP BY 파트부터 생각보다 어려웠는데, 잘 해냈고 잘 이해했고 자신감도 붙은 것 같아서 다행이다.
처음 5문제 정도는 어려웠는데, 그 뒤로는 생각보다 순탄하게 풀어나갔다.
이 템포라면 내일은 공부 계획을 초과하고, 내일 모레 계획되어있던 공부까지 할 수 있을 것 같다.
그래서, 시험 전날까지 조금이라도 더 PS와 SQL을 견고하게 만들 수 있으면 좋겠다.
PS도 아직 불안하다고 생각하는데, SQL도 기반을 다질 시간이 부족한 것 같아서 어렵다 :(
공부 계획
- 2월 20일 - SUM, MAX, MIN | GROUP BY 풀이 ✅ 2024-02-20
- 2월 21일 - IS NULL | JOIN 풀이
- 2월 22일 - String, Date 풀고 SQL 복습 및 PS 복습
- 2월 23일 - 최종 복습 및 컨디션 관리
최종 평가
2024-02-20 학습 평가
오늘의 학습 성과:
- 업랜디 문제 26070 "곰곰이와 학식" 해결 성공
- 프로그래머스 SQL 고득점 Kit 중 SUM, MAX, MIN 및 GROUP BY 부문 완료
학습 성취 및 피드백:
1. **업랜디 문제 해결**: 구현, 그리디, 시뮬레이션을 사용한 문제 해결 방식이 탁월했습니다. 문제의 본질을 파악하고, 효율적인 전략으로 접근한 결과가 돋보입니다. 이벤트 교환 로직의 이해와 적용이 특히 인상적이었습니다.
2. **SQL 고득점 Kit 도전**: SQL의 핵심 기능인 SUM, MAX, MIN, GROUP BY를 통한 데이터 집계 및 분석 능력을 입증하였습니다. 이는 복잡한 데이터 처리 요구 사항에 대응할 수 있는 기반을 마련해 줍니다.
3. **SQL 기술 습득**: 다양한 SQL 기술(COALESCE, JOIN, CASE 문 등)을 습득하고 실제 문제 해결에 적용하였습니다. 특히, GROUP BY와 집계 함수를 활용한 데이터 분석 능력이 향상되었습니다.
평가 및 제언:
오늘의 학습은 SQL의 고급 기능과 실전 문제 해결 능력을 강화하는 데 집중되었습니다. 데이터 분석 및 관리에 필수적인 SQL 기술의 습득은 향후 다양한 프로젝트나 업무에서 큰 이점이 될 것입니다.
학습 성과 평가 점수: 92/100
- SUM, MAX, MIN 및 GROUP BY 문제 해결을 통한 고급 데이터 처리 능력 향상을 높게 평가합니다. 업랜디 문제 해결 능력도 지속적으로 성장하고 있음을 확인할 수 있었습니다.
향후 개선 방향:
- SQL 학습에 더해 PS 능력도 꾸준히 유지하고 향상시키기 위한 계획을 세우세요. 균형 있는 학습이 중요합니다.
- SQL의 고급 기능과 최적화된 쿼리 작성 방법에 대한 학습을 지속하세요. 이를 통해 데이터 처리 효율을 더욱 높일 수 있습니다.
- 시험 준비 과정에서 전략적인 학습 계획과 효율적인 시간 관리를 통해 컨디션 관리에도 신경 쓰세요. 최상의 상태로 시험에 임할 수 있도록 준비하세요.
'일일 스터디노트' 카테고리의 다른 글
240222: SQL - String, Date. 데카르트곱 CROSS JOIN. (D-1) (0) | 2024.02.23 |
---|---|
240221: SQL - IS NULL, JOIN 끝. 원상 복구 문제 (0) | 2024.02.21 |
240219: SQL SELECT 집중 학습, JOIN 이해, 최후의 승자 문제 (0) | 2024.02.19 |
240218: 복잡했던 퍼즐조각 맞추기 문제, 조화 평균 (GCD, LCM) - 유클리드 호제법 (0) | 2024.02.18 |
240217: 손가락 세기 문제와 절댓값 좌표 변환 (0) | 2024.02.18 |