티스토리 뷰

SQL 코드카타

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

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/131537

2. 정답 코드:

SELECT
    SUBSTR(o.SALES_DATE, 1, 10) AS SALES_DATE,
    o.PRODUCT_ID,
    o.USER_ID,
    o.SALES_AMOUNT
FROM ONLINE_SALE AS o
WHERE SUBSTR(o.SALES_DATE, 1, 7) = '2022-03'
UNION
SELECT
    SUBSTR(off.SALES_DATE, 1, 10) AS SALES_DATE,
    off.PRODUCT_ID,
    NULL,
    off.SALES_AMOUNT
FROM OFFLINE_SALE AS off
WHERE SUBSTR(off.SALES_DATE, 1, 7) = '2022-03'
ORDER BY SALES_DATE, PRODUCT_ID, USER_ID;
UNION 사용해서 온라인+오프라인 동일 컬럼 안에 데이터 넣어야 함!
온라인 기준으로 UNION 하는거라 오프라인 테이블에는 없는 USER_ID가 있는데 이걸 문제 없이 합쳐주려면, 컬럼 자체를 NULL로 작성하면 된다! + 온라인과 동일하게 NULL에 별칭을 주는게 데이터 확인할 때 더 편하다(NULL AS USER_ID) 

 

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

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/164673

2. 정답 코드:

SELECT
    b.TITLE,
    b.BOARD_ID,
    r.REPLY_ID,
    r.WRITER_ID,
    r.CONTENTS,
    SUBSTR(r.CREATED_DATE, 1, 10) AS CREATED_DATE
FROM USED_GOODS_BOARD AS b
JOIN USED_GOODS_REPLY AS r
  ON b.BOARD_ID = r.BOARD_ID
WHERE SUBSTR(b.CREATED_DATE, 1, 7) = '2022-10'
ORDER BY r.CREATED_DATE, b.TITLE;

 

Q73. 입양 시각 구하기(2) ★ 재귀 쿼리(Recursive CTE)

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/59413

2. 정답 코드:

WITH RECURSIVE TIME_TABLE AS (
    SELECT 0 AS HOUR             -- 시작점 (0시)
    UNION ALL
    SELECT HOUR + 1 FROM TIME_TABLE 
    WHERE HOUR < 23              -- 23시까지 반복
)
SELECT
    t.HOUR,
    COUNT(a.ANIMAL_ID) AS COUNT
FROM TIME_TABLE AS t
LEFT JOIN ANIMAL_OUTS AS a
  ON t.HOUR = HOUR(a.DATETIME)
GROUP BY t.HOUR
ORDER BY t.HOUR

3. 오류 상황: HOUR 컬럼이 0~23으로 되어야 하는데 COUNT 값이 있는 시간만 표시됨

4. 시도 방법: Gemini를 활용하여 뭐가 틀렸는지 간단한 힌트만 달라고 함

5. 최종 문제 해결 방법: HOUR 컬럼이 0~23으로 표시될 수 있도록 먼저 재귀 쿼리를 만들고, UNION으로 기존 테이블과 합쳐줘야 한다!

재귀 쿼리(Recursive Query)
: CTE 종류 중 하나! → 전에 배웠던 CTE 쿼리처럼 처음 시작할 때 WITH ~ 적어줘야 함 
'재귀'라는 말처럼, 자기 자신을 계속 불러서 반복하는 규칙을 만드는 쿼리

생성형 AI 설명)

재귀 쿼리가 뭔지 위 문제를 기반으로 설명해보면,

WITH RECURSIVE TIME_TABLE AS (
    -- 1단계: 시작 (첫 번째 항)
    SELECT 0 AS HOUR 
    
    UNION ALL
    
    -- 2단계: 반복 규칙 (n번째 항에 1을 더해라)
    SELECT HOUR + 1 FROM TIME_TABLE 
    
    -- 3단계: 멈춤 (23이 될 때까지만 해라)
    WHERE HOUR < 23
)
  1. 컴퓨터가 처음엔 0을 딱 적는다.
  2. 그다음에 "어? 규칙이 있네? 앞의 숫자(0)에 1을 더하자" 해서 1을 만든다.
  3. 그다음엔 1에 1을 더해서 2를 만들고... 이걸 무한 반복할 것 같지만!
  4. 마지막에 적힌 WHERE HOUR < 23이라는 조건 덕분에 23이 되는 순간 "아, 여기까지구나!" 하고 멈춤

결과적으로 아무것도 없던 빈 바탕에 0, 1, 2, 3, ..., 23이라는 숫자가 적힌 가상의 수첩이 만들어진다.


그럼 왜 재귀 쿼리는 쓰는걸까?

보통 데이터베이스(DB)는 있는 데이터를 찾아주는 역할을 하는데, 위 예제처럼 "새벽 3시에 입양된 동물이 없어서 데이터 자체가 존재하지 않을 때"가 문제가 된다.

없는 데이터를 0이라고 말하려면, 기준이 되는 전체 숫자(0~23)가 필요하고, 이때 재귀 쿼리를 써서 우리가 직접 "0부터 23까지 적힌 가짜 장부"를 뚝딱 만들어낸다!


일반 CTE vs 재귀 CTE

구분 일반 CTE (Non-Recursive) 재귀 CTE (Recursive)
비유 사진 찍기 동영상 찍기 (움직임)
하는 일 있는 데이터를 잠시 옮겨 담아둠 규칙에 따라 데이터를 새로 만들어냄
작동 방식 "A 테이블에서 이름만 뽑아서 상자에 넣어줘" "0부터 시작해서 23까지 계속 1을 더해줘"
키워드 WITH 이름 AS (...) WITH RECURSIVE 이름 AS (...)

Q74. 특정 기간동안 대여 가능한 자동차들의 대여비용 구하기 ★어려움

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/157339

2. 정답 코드:

SELECT
    DISTINCT c.CAR_ID,
    c.CAR_TYPE,
    ROUND(c.DAILY_FEE * 30 * (1 - p.DISCOUNT_RATE/100), 0) AS FEE
FROM CAR_RENTAL_COMPANY_CAR AS c
JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY AS h
  ON c.CAR_ID = h.CAR_ID
  AND c.CAR_TYPE IN ('세단', 'SUV')
JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS p
  ON c.CAR_TYPE = p.CAR_TYPE
  AND p.DURATION_TYPE = '30일 이상'
WHERE c.CAR_ID NOT IN (
                    SELECT CAR_ID
                    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
                    WHERE START_DATE <= '2022-11-30' AND END_DATE >= '2022-11-01'
                    )
  AND ROUND(c.DAILY_FEE * 30 * (1 - p.DISCOUNT_RATE/100), 0) >= 500000
  AND ROUND(c.DAILY_FEE * 30 * (1 - p.DISCOUNT_RATE/100), 0) < 2000000
ORDER BY FEE DESC, c.CAR_TYPE ASC, c.CAR_ID DESC;

# 기간 설정을 WHERE 절에 서브쿼리 NOT IN으로!

3. 오류 상황: 조회 기간 설정을 못함

4. 시도 방법: h.END_DATE < '2022-11-01'로 해봤는데 틀림

5. 최종 문제 해결 방법: END_DATE 조건만 걸면 한 자동차가 여러 번의 대여기록이 있을 수 있기 때문에 기간 필터링이 제대로 되지 않는다. 문제가 될 수 있는 경우는 아래와 같다.

  • 10월 1일 ~ 10월 5일 (반납 완료)
  • 10월 25일 ~ 11월 15일 (현재 대여 중)

이러면 해당 자동차는 '2022-10-05' < '2022-11-01' 이기 때문에 대여 가능한 자동차로 인식된다. 그렇지만 그 이후의 기록을 보면 이미 11월에 대여 중이기 때문에 대여 불가한 자동차이다!

그래서 WHERE 절에서 START_DATE가 '2022-11-30' 이전이고, END_DATE가 '2022-11-01' 이후인, 즉 11월에 이미 대여가 되어 있는 자동차의 ID를 NOT IN으로 제거해버리면 원하는 결과를 얻을 수 있다.

 

근데 여기에서 실무 수준으로 생각하면 불필요한 조인을 제거하는 것이 데이터 중복을 줄여 처리 속도를 단축시킬 수 있다고 한다!

SELECT
    c.CAR_ID, -- JOIN h를 안 하면 데이터 중복이 안 생겨서 DISTINCT도 필요 없어짐!
    c.CAR_TYPE,
    ROUND(c.DAILY_FEE * 30 * (1 - p.DISCOUNT_RATE/100), 0) AS FEE
FROM CAR_RENTAL_COMPANY_CAR AS c
-- HISTORY 테이블 조인 생략!
JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS p
  ON c.CAR_TYPE = p.CAR_TYPE
  AND p.DURATION_TYPE = '30일 이상'
WHERE c.CAR_TYPE IN ('세단', 'SUV') -- 차종 조건은 여기서!
  AND c.CAR_ID NOT IN ( -- 11월 대여 중인 차들만 여기서 체크!
        SELECT CAR_ID
        FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
        WHERE START_DATE <= '2022-11-30' AND END_DATE >= '2022-11-01'
  )
  AND (FEE 계산식 조건...)
ORDER BY FEE DESC, c.CAR_TYPE ASC, c.CAR_ID DESC;
문제 난이도가 급격히 올라가서 문제 이해부터 오래 걸렸다,, 당연히 JOIN을 2번 해야한다고 생각했는데 간단히 할 수 있는 방법이 있어서 앞으로는 쿼리를 간략하게 만들 수 있는 방법이 있는지 검토해 봐야겠다.

 

Q75. 자동차 대여 기록 별 대여 금액 구하기 ★어려움

1. 문제 링크: https://school.programmers.co.kr/learn/courses/30/lessons/151141

2. 정답 코드:

SELECT 
    h.HISTORY_ID,
    ROUND(c.DAILY_FEE * (DATEDIFF(h.END_DATE, h.START_DATE)+1) * (1 - IFNULL(p.DISCOUNT_RATE, 0) / 100), 0) AS FEE
FROM CAR_RENTAL_COMPANY_CAR AS c
JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY AS h
  ON c.CAR_ID = h.CAR_ID
  AND c.CAR_TYPE = '트럭'
LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS p
  ON c.CAR_TYPE = p.CAR_TYPE
  AND p.DURATION_TYPE = (
    CASE
      WHEN DATEDIFF(h.END_DATE, h.START_DATE)+1 >= 90 THEN '90일 이상'
      WHEN DATEDIFF(h.END_DATE, h.START_DATE)+1 >= 30 THEN '30일 이상'
      WHEN DATEDIFF(h.END_DATE, h.START_DATE)+1 >= 7 THEN '7일 이상'
      ELSE NULL
    END 
  )
ORDER BY FEE DESC, h.HISTORY_ID DESC;

# CASE WHEN 문을 활용해 DURATION_TYPE 이름표를 달아준다!

3. 오류 상황: DISCOUNT_RATE 매칭을 하는 방법을 잘 모르겠음

4. 시도 방법: Gemini를 활용하여 뭐가 틀렸는지 간단한 힌트만 달라고 함

5. 최종 문제 해결 방법: 각 HISTORY_ID 별 매칭되는 DISCOUNT_RATE를 찾기 위해서는 그 중간에 이름표 역할을 하는 DURATION_TYPE이 필요하다! 그렇기 때문에 테이블 JOIN할 때 ON 조건으로 CASE WHEN 문을 작성해서 이름표를 붙여줘야만 한다. 이 때, 7일 미만 대여할 경우 할인율이 없기 때문에 INNER JOIN이 아닌 LEFT JOIN으로 NULL 값을 남겨놓아야 하고, 이 NULL 값이 실제 FEE 계산식에서 오류를 발생시키지 않도록 IFNULL(DISCOUNT_RATE, 0) 으로 바꿔줘야 한다!


문제 풀 때, 최종적으로는 DISCOUNT_RATE가 필요한건데 왜 JOIN 조건에 DURATION_TYPE을 주는지 이해가 되지 않았다.

이 부분을 생성형 AI에게 물어보았다!

 

생성형 AI 설명)

"필요한 건 DISCOUNT_RATE인데 왜 굳이 DURATION_TYPE이라는 이름표를 거쳐서 가느냐"는 의문이 드는 게 당연해요.

이해를 돕기 위해 '도서관'이나 '마트'의 상황에 비유해서 설명해 드릴게요.


1. 테이블은 '별도의 방'에 살고 있어요

우리가 가진 정보는 두 개의 서로 다른 방에 나뉘어 있습니다.

  • 방 A (대여 기록): "이 트럭은 15일 동안 빌려갔어." (숫자 정보만 있음)
  • 방 B (할인 정책): "'7일 이상' 빌리면 5% 할인해 줄게." (이름표와 할인율이 세트로 있음)

우리가 원하는 건 5%(DISCOUNT_RATE)지만, 방 B로 가서 "15일 빌렸는데 얼마 할인해 줘?"라고 물어보면 방 B는 대답을 못 합니다. 방 B의 장부에는 '15'라는 숫자가 없고 오직 '7일 이상', '30일 이상', '90일 이상'이라는 글자(이름표)만 적혀 있기 때문이죠.


2. 중간 다리 역할: DURATION_TYPE

그래서 우리는 중간 다리를 놓아야 합니다.

  1. 변환 (CASE 문): 먼저 15라는 숫자를 방 B가 알아들을 수 있는 언어인 '7일 이상'으로 바꿉니다.
  2. 연결 (JOIN): "방 B야, 여기 '7일 이상'이라는 이름표가 있어. 이거랑 똑같은 글자가 적힌 줄을 보여줘."라고 말하는 과정이 바로 p.DURATION_TYPE = (CASE ...) 입니다.
  3. 획득 (SELECT): 드디어 방 B에서 그 줄에 적힌 5%(DISCOUNT_RATE)를 꺼내올 수 있게 되는 거죠.

3. 만약 DURATION_TYPE을 안 거치고 바로 찾으려면?

질문하신 것처럼 DISCOUNT_RATE를 바로 찾으려면, JOIN을 쓰지 않고 SELECT 문 안에 아주 긴 서브쿼리를 넣어야 합니다.

-- (비효율적인 예시)
SELECT 
    (SELECT DISCOUNT_RATE FROM DISCOUNT_PLAN 
     WHERE DURATION_TYPE = (CASE WHEN ... THEN '7일 이상' ... END)) AS RATE
...

하지만 이렇게 하면 컴퓨터가 모든 행마다 매번 방 B에 가서 일일이 검색해야 하므로 속도가 굉장히 느려집니다. 대신 JOIN 조건에 이름표(DURATION_TYPE)를 딱 걸어두면, 컴퓨터가 두 테이블을 미리 착 붙여놓고 한 번에 계산하기 때문에 훨씬 효율적이에요.


라이브 세션) Python 기초 강의 7일차 - 수업날 [함수, 모듈]

1) 함수

def = definition 함수 정의하고 들어간다-!

def 함수이름(매개변수1, 매개변수2, ...):
    # 함수가 수행할 문장들
    # ...
    return 반환값 

- return 문은 생략 가능하며, 이 경우 함수는 None을 반환

- 매개 변수 자리에 인자를 넣어서 원하는 출력을 얻어낸다!

def add(a, b)  # a, b는 매개변수(parameter)
	return a + b
    
result = add(3, 5)  # 3과 5는 인자(argument)

print(result)  # 출력: 8

 

반환값(Return Value)

: return 키워드를 만나면 함수는 즉시 종료되고, 그 뒤의 코드는 실행되지 않는다. 

반환값은 없을 수도 있고 1개 또는 여러 개일 수도 있다!

 

(1) 반환값 0개

def greet(name):
    print("Hello,", name)
    # return 문이 없으므로 None 반환

greet("Alice")  # "Hello, Alice"를 출력하고 반환값은 None

 

(2) 반환값 1개

def square(x):
    return x * x

result = square(4)
print(result)  # 16

 

(3) 반환값 2개

def divide_and_remainder(a, b):
    quotient = a // b  # 몫
    remainder = a % b  # 나머지
    return quotient, remainder

q, r = divide_and_remainder(10, 3)
print("몫:", q)   # 몫: 3
print("나머지:", r) # 나머지: 1
◦ 함수 끝 조건 : return ~ → ~를 리턴하면서 종료
◦ return : → None을 리턴하면서 종료
◦ return 없음 : → None을 리턴하면서 종료

 

매개변수 전달 방식

(1) 기본 매개변수(Default Parameter)

def greet(name, message="Hello"):
    print(message, name)

greet("Alice")        # "Hello Alice" - message에 기본값 사용
greet("Bob", "Hi")     # "Hi Bob"

→ message = "Hello" 로 기본값을 지정해서 greet("Alice") 처럼 message 인자가 들어오지 않아도 기본값으로 출력해줌! 

 

그런데, 유사하지만 다른 값을 보이는 아래 코드를 살펴보면 마지막 줄에서 None을 출력하는 것을 확인할 수 있다.

def greet(name, message="Hello"):
    print(message, name)

greet("Bob", "Hi")     # "Hi Bob"

print(greet("Bob", "Hi))    # None

 

print(greet("Bob", "Hi")) 코드는 다음과 같은 순서로 작동한다.

  1. 함수 호출: greet("Bob", "Hi")가 실행됨
  2. 화면 출력: 함수 내부의 print(message, name)이 실행되어 화면에 "Hi Bob"이 출력됨
  3. 반환 단계: 함수의 코드가 끝났는데 return문이 없다? 파이썬은 이럴 때 몰래 return None을 수행
  4. 최종 출력: 이제 원래의 문장은 print(None)이 되어버려서 화면에 None이 추가로 출력됨
None이 출력된 이유는 화면에 글자를 보여주는 동작(print)은 성공했지만, 함수가 끝난 뒤 남긴 값(return)이 아무것도 없었기 때문이다!

 

(2) 키워드 인자(Keyword Argument) : 매개변수 이름을 명시해서 인자 전달

def introduce(name, age):
    print("이름:", name)
    print("나이:", age)

introduce(name="Charlie", age=25)
introduce(age=30, name="Diana")  # 순서를 바꿔도 명시적이라 오류 없음

 

Docstring(문서 문자열)

"""(삼중 따옴표) 표시해서 함수에 대한 설명을 작성한다!

def add(a, b):
	"""두 수를 더한 값을 반환하는 함수"""
    return a + b

 

지역 변수와 전역 변수

: 함수 내부에서만? 지역 변수, 코드 전체에서? 전역 변수

x = 10  # 전역 변수

def my_func():
    x = 5  # 지역 변수
    print("함수 내부:", x)

my_func()         # 함수 내부: 5
print("함수 외부:", x)  # 함수 외부: 10

실습 문제 1 : 리스트의 합 list_sum

문제 설명

  • 정수로만 이루어진 리스트 nums를 매개변수로 받아 모든 요소의 합을 반환하는 함수를 만드세요.
  • 리스트가 비어 있다면 0을 반환해야 합니다.
# 실습 문제 1

def list_sum(nums) :
  if len(nums) == 0 :
    return 0
  return sum(nums)

print(list_sum([1, 2, 3, 4]))
print(list_sum([]))

코드 실행 결과

 

실습 문제 2 : 단어 빈도 세기 함수 word_count

문제 설명

  • 문자열을 매개변수로 받아, 공백을 기준으로 단어를 분리합니다.
  • 각 단어가 몇 번 나왔는지 딕셔너리 형태로 반환하세요.
  • 대소문자는 구분하지 않으며, 모두 소문자로 변환한 뒤 계산하세요.
# 실습 문제 2

def word_count(s) :
  s = s.lower()  #소문자로 변경
  words = s.split()

  word_dict = {}

  for word in words :
    if not word in word_dict :
      word_dict[word] = 1
    else :
      word_dict[word] += 1

  return word_dict


print(word_count("Apple banana apple Orange orange banana apple"))

코드 실행 결과

# 실습 문제 2 - count 사용
# 리스트.count(찾고 싶은 값) = 이 리스트 안에 찾고 싶은 값이 몇개 있는지

def word_count(s) :
  s = s.lower()  #소문자로 변경
  words = s.split()
  print(words)

  word_dict = dict.fromkeys(words, 0)

  for word in words :
    word_dict[word] = s.count(word)

  return word_dict

word_count("Apple banana apple Orange orange banana apple")
리스트.count(찾고 싶은 값) = 이 리스트 안에 찾고 싶은 값이 몇개 있는지
dict.fromkeys(키로 만들고 싶은 리스트, 해당 키의 value 값)

# 리스트.count(찾고싶은값) = 이 리스트 안에 '찾고싶은값' 이 몇개있는지

def word_count(s) :
  s = s.lower()
  words = s.split()
  print(words)

  unique_words = list(set(words))
  print(unique_words)

  word_dict = dict.fromkeys(unique_words, 0)

  for word in unique_words :
    word_dict[word] = s.count(word)

  return word_dict

word_count("Apple banana apple Orange orange banana apple")

 

실습 문제 3 : 학점 계산 함수 grade_report

문제 설명

  • 학생 이름과 점수가 들어있는 딕셔너리를 매개변수로 받으세요.
  • 점수를 기준으로 학점(A, B, C, D, F)을 매겨서 새 딕셔너리로 반환하세요.
  • 학점 기준은 다음과 같습니다.
점수 범위 학점
90 이상 A
80~89 B
70~79 C
60~69 D
60 미만 F
# 실습 문제 3

def grade_report(student_info) :

  grade_dict = {}

  for name in student_info.keys() :
      score = student_info[name]

      if score >= 90 :
        grade_dict[name] = "A"
      elif score >= 80 :
        grade_dict[name] = "B"
      elif score >= 70 :
        grade_dict[name] = "C"
      elif score >= 60 :
        grade_dict[name] = "D"
      else :
        grade_dict[name] = "F"

  return grade_dict

# 딕셔너리, 리스트의 특성 : 함수 안에서나 밖에서나 통용되는 특징이 있다.
scores = {"Alice": 85, "Bob": 92, "Charlie": 67, "Dave": 58}
print(grade_report(scores))

코드 실행 결과


2) 모듈

: 다른 파이썬 프로그램에서 불러와서 쓸 수 있는 파이썬 파일(.py)

# mymodule.py (모듈 예시)
def add(a, b):
    return a + b

def subtract(a, b):
    return a - b

PI = 3.14159
모듈을 사용하려면 import를 먼저 해줘야 한다!

 

모듈을 사용하는데는 크게 2가지 방법이 있는데,

(1) 모듈 전체 사용하기

import math  # 수학 관련 기능이 담긴 math 모듈을 가져옴

print(math.pi)       # math 모듈 안의 pi(원주율) 사용
print(math.sqrt(16)) # math 모듈 안의 sqrt(제곱근) 함수 사용

 

(2) 필요한 것만 골라서 가져오기

from math import pi, sqrt

print(pi)    # math. 을 붙일 필요 없이 바로 사용 가능
print(sqrt(16))

미니 세션) AI를 활용한 효과적인 공부법

- RAG : Retrieval Augmented Generation (검색 증강 생성)

→ 자료(인터넷, DB, 우리가 첨부한 PDF, 텍스트 등)에 기반해서 답변을 하는 기술

→ AI 환각 현상을 줄이고 공식 문서에 근거해서 답변을 함

→ RAG를 효과적으로 이용한 서비스가 NoteBookLM, 퍼플렉시티

 

- 베스트 프래틱스(Best Practice) : 주로 IT 계열에서 좋은 예시를 의미

특정 분야에서 가장 효과적이고 성공적인 방법이나 접근 방식을 뜻하며, 경험과 연구에 기반한 효율적인 방법

 

- 엣지 케이스(Edge Case) : 알고리즘이 처리하는 데이터가 허용 범위를 벗어나거나 경계값에 도달했을 때 발생할 수 있는 예외 상황


오늘은 함수와 모듈을 학습했는데, 아직 pandas나 numpy 같은 라이브러리를 배우지 않아 개념을 얕은 수준에서만 다루게 되었다. 추후 라이브러리를 본격적으로 학습하게 되면, 이 부분은 다시 한 번 복습해야 할 것 같다.

또 SQL 코드카타를 5문제 풀었는데, 문제 난이도가 많이 높아지면서 해결에 생각보다 많은 시간이 소요됐다. 그래서 내일부터는 하루 2~3문제로 양을 조절하고, 대신 한 문제씩 더 깊이 있게 분석하며 학습하려 한다. 추가로 파이썬 코드카타도 병행하면서, GitHub에 직접 파일을 업로드하는 연습도 해봐야겠다.

주말에 예상치 못한 일이 생겨 추가 공부를 충분히 하지 못했지만, 주중에 틈틈이 시간을 내어 유튜브 강의도 함께 들으며 보완할 계획이다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함