Today I Learn
: SQL 코드카타, 수업날 강의, 복습, 아티클 스터디
- SQL 코드카타
- 문제 1
1. 문제 링크: https://leetcode.com/problems/patients-with-a-condition/
2. 정답 코드:
select patient_id, patient_name, conditions
from Patients
where conditions like '%DIAB1%'
select patient_id, patient_name, conditions
from Patients
where conditions regexp '^DIAB1| DIAB1'
- %DIAB1%만 사용하면 명확한 DIAB1을 찾지 못하고 다른 문자에 연결된 PEDIAB1과 같은 경우도 함께 조회함
- 더 명확성 강화를 위해 DIAB1이 맨 처음 나오는 경우나 공백 다음에 나오는 경우로 한정해야함!
- like or을 사용할 경우 더 경우의 수가 많아지면 쿼리가 과하게 길어질 수 있음
- → regexp 사용!
- ^ : 문자열 맨 처음에 위치
- | : or 의미
- 문제 2
1. 문제 링크: https://www.hackerrank.com/challenges/revising-the-select-query/problem
2. 정답 코드:
select *
from CITY
where population > 100000 and countrycode = 'USA'
- 문제 3
1. 문제 링크: https://www.hackerrank.com/challenges/revising-the-select-query-2/problem
2. 정답 코드:
select name
from city
where countrycode = 'USA' and population > 120000
- 문제 4
1. 문제 링크: https://www.hackerrank.com/challenges/select-all-sql/problem
2. 정답 코드:
select *
from city
- 문제 5
1. 문제 링크: https://www.hackerrank.com/challenges/select-by-id/problem
2. 정답 코드:
select *
from city
where id = '1661'
- 문제 6
1. 문제 링크: https://www.hackerrank.com/challenges/japanese-cities-attributes/problem
2. 정답 코드:
select *
from city
where countrycode = 'JPN'
- 문제 7
1. 문제 링크: https://www.hackerrank.com/challenges/japanese-cities-name/problem
2. 정답 코드:
select name
from city
where countrycode = 'JPN'
- 문제 8
1. 문제 링크: https://www.hackerrank.com/challenges/weather-observation-station-1/problem
2. 정답 코드:
select city, state
from station
- 문제 9
1. 문제 링크: https://www.hackerrank.com/challenges/name-of-employees/problem
2. 정답 코드:
select name
from employee
order by name
- 문제 10
1. 문제 링크: https://www.hackerrank.com/challenges/salary-of-employees/problem
2. 정답 코드:
select name
from employee
where salary > 2000 and months < 10
order by employee_id asc
- 문제 11
1. 문제 링크: https://www.hackerrank.com/challenges/revising-aggregations-the-count-function/problem
2. 정답 코드:
select count(*)
from city
where population > 100000
- 문제 12
1. 문제 링크: https://www.hackerrank.com/challenges/revising-aggregations-sum/problem
2. 정답 코드:
select sum(population)
from city
where district = 'California'
- 문제 13
1. 문제 링크: https://www.hackerrank.com/challenges/revising-aggregations-the-average-function/problem
2. 정답 코드:
select avg(population)
from city
where district = 'California'
- 문제 14
1. 문제 링크: https://www.hackerrank.com/challenges/average-population/problem
2. 정답 코드:
select round(avg(population),0)
from city
- 문제 15
1. 문제 링크: https://www.hackerrank.com/challenges/japan-population/problem
2. 정답 코드:
select sum(population)
from city
where countrycode = 'JPN'
- 문제 16
1. 문제 링크: https://www.hackerrank.com/challenges/population-density-difference/problem
2. 정답 코드:
select max(population)-min(population)
from city
- 문제 17
1. 문제 링크: https://leetcode.com/problems/replace-employee-id-with-the-unique-identifier/submissions/1884409345/
2. 정답 코드:
select
u.unique_id, e.name
from employees e
left join employeeuni u
on e.id = u.id
- 문제 18
1. 문제 링크: https://leetcode.com/problems/product-sales-analysis-i/description/
2. 정답 코드:
select p.product_name, s.year, s.price
from sales s
join product p
on p.product_id = s.product_id
- 문제 19
1. 문제 링크: https://leetcode.com/problems/customer-who-visited-but-did-not-make-any-transactions/description/
2. 정답 코드:
select v.customer_id, count(*) as count_no_trans
from visits v
left join transactions t
on v.visit_id = t.visit_id
where t.transaction_id is null
group by v.customer_id
select v.customer_id, count(*) as count_no_trans
from visits v
where not exists (
select 1
from transactions t
where t.visit_id = v.visit_id
)
group by v.customer_id
- left join 을 하면 불필요하게 두 테이블을 합친 후 또 그 중에 is null 인 것만 추출하게 됨 (메모리 낭비)
- → not exists를 사용해서 transactions 테이블에 없으면서 visits 에만 있는 행을 추출하기
- 문제 20
1. 문제 링크: https://leetcode.com/problems/rising-temperature/
2. 정답 코드:
with selected as (
select
id,
temperature - lag(temperature,1,temperature)
over (order by recordDate) as difference
from weather
)
select id
from selected
where difference > 0
3. 오류 상황: 하루 전의 데이터가 없을 경우, yesterday가 아니더라도 날짜 순서로 정렬했을 때 그 전 행에 해당하는 값을 불러오는 것이므로 문제 조건에 맞지 않음 (문제에선 yesterday 일 때 그 값이랑 비교하는 조건!)
4. 해결 방안: lag 윈도우 함수를 사용하지 말고 날짜 자체를 비교하는 함수를 사용해야함 (datediff / subdate)
select w1.id
from weather w1
join weather w2
on datediff(w1.recorddate, w2.recorddate) = 1
where w1.temperature > w2.temperature
select w1.id
from weather w1
join weather w2
on w2.recorddate = subdate(w1.recorddate,1)
where w1.temperature > w2.temperature
select w1.id
from weather w1
where exists (
select 1
from weather w2
where w2.recordDate = subdate(w1.recordDate, 1) -- w2 : 날짜가 하루 전이고
and w1.temperature > w2.temperature -- 온도가 더 낮은지 확인
)
- where exists 함수 사용할 때
- subdate(날짜, interval) : 날짜 보다 interval 이전인 날짜 리턴
- → 하루 전 날짜 리턴
- 파이썬 수업날 복습 (클래스|파일)
- 함수만 쓸 때 vs 클래스를 쓸 때
- 함수만 쓰면: 데이터랑 기능이 흩어져서 사람이 기억해야 하는 코드
- 클래스 쓰면: 현실 세계처럼 물건 단위로 정리된 코드
- __init__ 생성자
- 인스턴스가 생성될 때 자동으로 호출되는 메서드
- 생성될 때 호출된다고 해서 생성자(constructor)라고도 불림
- 인스턴스 변수 (instance variable)
- 각 객체마다 별도로 관리되는 변수
- self.name, self.age와 같이 self를 통해 참조하는 변수
- 각각 인스턴스 마다 각각 값을 가질 수 있음
- 클래스 변수 (class variable)
- 클래스로부터 만들어진 모든 인스턴스가 공유하는 변수
- 클래스 블록 내에서 self 없이 바로 변수를 정의하면 클래스 변수로 설정됨
class Car:
wheels = 4 # 클래스 변수: 모든 Car 인스턴스는 바퀴가 4개
def __init__(self, color):
self.color = color # 인스턴스 변수: 각 차마다 색이 다를 수 있음
car1 = Car("red")
car2 = Car("blue")
print(car1.color) # "red" (car1만의 인스턴스 변수)
print(car2.color) # "blue" (car2만의 인스턴스 변수)
print(car1.wheels) # 4 (클래스 변수는 모든 객체가 공유)
print(car2.wheels) # 4
- car1.wheels = 3 를 하면
- car1에만 새로운 인스턴스 변수를 만드는 것
- Car.wheels 는 그대로 4임
- 인스턴스 메서드 (Instance Method)
- 첫 번째 매개변수로 self 받음
- 각 인스턴스에 대해서 동작하며, 인스턴스 변수를 다루는 데 주로 사용함
class Person:
def __init__(self, name):
self.name = name
def say_hello(self): #인스턴스 메서드
print(f"Hello, my name is {self.name}")
person1 = Person("alice")
person1.say_hello()
- 클래스 메서드 (Class Method)
- 첫 번째 매개변수로 cls 받음 (self 대신 cls 키워드 사용)
- 데코레이터 @classmethod 사용
- 클래스 자체를 인자로 받음
- 활용: 클래스 변수를 다루는 상황 / 새로운 인스턴스를 생성하는 메서드 등을 정의
class Person:
count = 0
def __init__(self, name):
self.name = name
Person.count += 1
@classmethod
def how_many(cls):
print(f"지금까지 {cls.count}명이 만들어졌습니다.")
p1 = Person("Alice")
p2 = Person("Bob")
Person.how_many() # "지금까지 2명이 만들어졌습니다."
- 정적 메서드 (Static Method)
- 첫 번째 매개 변수로 self나 cls 받지 않음
- 사실 클래스에 굳이 소속될 필요 없음. but '분류상' 틀에 넣어야 깔끔해서 넣는 것.
(주로 클래스나 인스턴스 변수에 접근할 필요가 없는 경우) - 데코레이터 @staticmethod 사용
class MathUtils:
@staticmethod
def add(a, b):
return a + b
result = MathUtils.add(3, 5)
print(result) # 8
- 접근 지정자와 캡슐화
- Java나 C++의 접근 지정자(Public, Protected, Private)와 달리 파이썬에서는 안더스코어를 붙여 사용함
| 구분 | Java / C++ (키워드 방식) | Python (언더스코어 방식) | 의미 |
| Public | public int age; | self.age | 누구나 접근 가능 (기본값) |
| Protected | protected int age; | self._age | [관례] 클래스 내부와 상속 관계에서만 쓰자고 약속함 |
| Private | private int age; | self.__age | [강제성 있음] 이름 변형을 통해 외부 접근을 막음 |
- _variable (Weak Internal Use)
- 문법적으로는 Public과 똑같음. 밖에서 호출해도 에러 안남
- '이건 이 클래스 내부 구현을 위한거니까, 밖에서 직접 수정하면 코드가 꼬일 수 있어.'라고 경고를 주는 것
- __variable (Strong Private)
- "이 변수는 이 클래스 내에서만 쓰겠다. 상속 받은 자식 클래스 조차도 함부로 못 건드리게 하겠다."
- 자식 클래스에게 공유하고 싶다면 _ 하나만 쓰기!
- Name Mangling이 일어남
- self.__password라고 선언하면, 파이썬은 내부적으로 이름을 _ClassName__password로 바꿔버림
- 외부에서 acc.__password라고 치면 '그런 이름은 없다'는 AttributeError 발생함
- "이 변수는 이 클래스 내에서만 쓰겠다. 상속 받은 자식 클래스 조차도 함부로 못 건드리게 하겠다."
class BankAccount:
def __init__(self, owner, balance, password):
self.owner = owner
self.__balance = balance # 이 변수는 직접 접근하기 어렵게 함
self.__password = password
def deposit(self,amount):
self.__balance += amount
def withdraw(self, amount):
if self.__balance >= amount:
self.__balance -= amount
else:
print("잔고 부족")
def get_balance(self):
return self.__balance
def get_password(self):
return self.__password
def change_password(self,pw):
self.__password = pw
acc = BankAccount("Alice",1000,12345)
print(acc.get_balance())
acc.deposit(500)
print(acc.get_balance())
acc.withdraw(2000)
print(acc.get_balance())
print(acc.get_password())
acc.change_password(54321)
print(acc.get_password())
print(acc.owner)
print(acc._BankAccount__password) # name mangling
- 상속 (Inheritance)
- 기존 클래스를 재사용하여 새로운 클래스를 만들 수 있게 하는 기능
- 상속을 통해 기존 클래스(부모 클래스 또는 슈퍼 클래스)의 변수 & 메서드를
- 자식 클래스(서브 클래스)에서 물려 받을 수 있음
- 필요하다면 물려받은걸 확장 또는 수정도 할 수 있음
- 다형성 (Polymorphism) & 오버라이딩 (Overriding)
- 다형성
- 같은 메서드 이름이 다양한 클래스에서 다른 형태로 동작할 수 있음을 의미
- 오버라이딩
- 자식 클래스에서 부모 클래스의 메서드를 재정의하는 것
class Animal:
def speak(self):
print("동물 소리")
class Cat(Animal):
def speak(self):
print("야옹")
class Dog(Animal):
def speak(self):
print("멍멍")
animals = [Cat(), Dog(), Animal()]
for a in animals:
a.speak()
# Cat 인스턴스 -> "야옹"
# Dog 인스턴스 -> "멍멍"
# Animal 인스턴스 -> "동물 소리"
- 실습 문제 1
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self,dx,dy):
self.x += dx
self.y += dy
return self
def show(self):
print(f"Point({self.x}, {self.y})")
p = Point(1,2)
p.move(2,3).show()
- move 메서드에 return self 를 추가하여
- move 의 결과값을 변수에 따로 저장할 필요 없이
- 한 줄로 p.move(2,3).show() 작성
https://myun0506.tistory.com/57
클래스
- 함수만 쓸 때 vs 클래스를 쓸 때함수만 쓰면: 데이터랑 기능이 흩어져서 사람이 기억해야 하는 코드클래스 쓰면: 현실 세계처럼 물건 단위로 정리된 코드- __init__ 생성자인스턴스가 생성될 때
myun0506.tistory.com
- 파일 열기 (open 함수)
file_object = open("파일이름", "모드")
- 주요 모드 종류
- "r": 읽기 전용 모드(기본값). 해당 파일이 존재하지 않으면 에러 발생
- "w": 쓰기 전용 모드. 파일이 존재하면 내용을 모두 지우고, 존재하지 않으면 새로 만듦
- "a": 추가(append)모드. 파일의 끝에 새로운 내용을 덧붙임. 파일이 없으면 새로 만듦
- "x": 쓰기 전용으로 새 파일을 만들기 위한 모드. 파일이 이미 존재하면 에러 발생
- "r+": 읽기/쓰기 겸용 모드. 기존 파일에 대해 읽고 쓰기 모두 가능
- "b": 바이너리 모드. "rb", "wb" 등의 형태로 다른 모드와 조합하여, 텍스트가 아닌 이미지, 음악 파일 등 이진 데이터 처리 시 사용
- "t": 텍스트 모드(기본값). "r","w" 등이 기본적으로 "t" 모드임
- 파일 읽기
- 읽기 모드("r")로 연 파일에 대해 다음과 같은 메서드를 사용해서 내용을 읽을 수 있음
- read() : 파일 전체 내용을 문자열로 읽어옴
- readline() : 파일에서 한 줄씩 읽어옴
- readlines() : 파일 전체 내용을 한 줄씩 나누어 리스트로 반환
file = open("example.txt", "r", encoding="utf-8") # UTF-8 인코딩 지정 가능
content = file.read() # 파일 전체 읽기
print(content)
line = file.readline() # 첫 번째 줄 읽기
print(line)
line = file.readline() # 두 번째 줄 읽기
print(line)
lines = file.readlines() # 모든 줄을 읽어 리스트로 반환
for l in lines:
print(l.strip()) # strip()으로 양 끝 공백 제거
file.close()
- 파일 쓰기
- 파일에 쓰기 위해서는 "w", "a", "r+", "x" 등 쓰기 기능이 지원되는 모드로 열어야 함
- "w" 모드: 기존 내용을 모두 지우고 새로 쓰기 시작함
- "a" 모드: 기존 파일의 끝에 내용을 이어 붙임
- with 문을 이용한 파일 처리
- with 문 사용하면 블록이 끝날 때 자동으로 파일을 닫아주기 때문에 close()를 깜빡하는 실수를 방지할 수 있음
with open("example.txt", "r", encoding="utf-8") as f:
content = f.read()
print(content)
# 여기서는 with 블록을 빠져나가면 f가 자동으로 close() 처리됩니다.
# 쓰기 예시
with open("output.txt", "w", encoding="utf-8") as f:
f.write("안녕하세요!\n")
f.write("이 내용은 output.txt에 쓰여집니다.\n")
# with 블록 종료 시 자동으로 f.close() 호출
- 바이너리 파일 다루기
- 이미지, 오디오, 영상, PDF 등 텍스트로 이루어지지 않은 파일은 바이너리 모드("b")로 열어야함
# 이미지 파일 복사 예제
with open("image.jpg", "rb") as src:
data = src.read()
with open("copy.jpg", "wb") as dst:
dst.write(data)
- "rb"로 원본 이미지를 읽고, "wb"로 복사본 작성함
- 텍스트 인코딩 관련 인자는 필요 없음
- 예외 처리
- 파일이 존재하지 않거나 경로가 잘못된 경우
- 권한 부족으로 파일을 열 수 없는 경우
- 디스크 문제가 발생한 경우
- → try-except 구문 사용
try:
with open("nonexistent.txt", "r", encoding="utf-8") as f:
data = f.read()
print(data)
except FileNotFoundError:
print("파일을 찾을 수 없습니다.")
except PermissionError:
print("파일에 접근할 권한이 없습니다.")
https://myun0506.tistory.com/58
파일 열기/읽기/쓰기, 주요 모드, with문을 활용한 파일 처리, 예외처리
- 파일 열기 (open 함수)file_object = open("파일이름", "모드") 주요 모드 종류"r": 읽기 전용 모드(기본값). 해당 파일이 존재하지 않으면 에러 발생"w": 쓰기 전용 모드. 파일이 존재하면 내용을 모두 지
myun0506.tistory.com
- 아티클 스터디 : 파이썬 초보자가 저지르는 10가지 실수
(https://yozm.wishket.com/magazine/detail/1605/)
- 요약
- 파이썬을 처음 접하는 초보자들이 많이 저지르는 실수와 이를 고칠 수 있는 방법을 설명한다
- 주요 포인트 (나쁜 습관들과 이를 고칠 수 있는 방법 제시)
- import * 사용
- 비효율적임
- 변수명에 충돌을 일으킬 수 있음
- → import math \n from math import pi 로 특정 객체를 불러오거나
- → import math 처럼 전체 모듈을 불러온 후 객체 사용 전에 math.floor 처럼 모듈 명을 명시
- 예외 처리 except 절에 예외를 지정하지 않음
- try/except 를 사용할 때에는 except 절에 예외를 꼭 지정하기
- 수학 계산에 Numpy를 사용하지 않음
- 수학 연산에 있어 빠르고 효율적인 작업!!!
- 수학 연산에는 Numpy 사용하기
- 이전에 열었떤 파일을 닫지 않음
- write/read 메소드 사용할 때 예외 발생하면 이미 열린 파일은 닫히지 않는 등의 문제 발생할 수 있음
- with 구문 사용하면 예외 발생하더라도 파일을 정상적으로 자동으로 닫아줌
- PEP8의 가이드라인을 벗어남
- 코드 작성에 대한 최고의 코드 샘플과 가이드라인 제공
- → 권장하는대로 따르기
- 딕셔너리 사용할 때 .keys와 .values 적절하게 사용하지 않음
- .keys 사용하지 않고 딕셔너리 반복만으로도 key 값을 얻을 수 있음
- value 값 얻어야할 땐 .items() 사용하면 효율적임
- 컴프리헨션을 사용하지 않음 (혹은 언제나 사용)
- for-loop 대신 리스트 컴프리헨션으로 간단히 처리하기
- but 남용하진 말기
- range(len()) 사용
- 인덱스와 반복 객체를 둘다 불러오고 싶을 떈 enumerate 사용하기
- 두가지 리스트를 함께 반복하는 경우엔 zip이 더 효율적임
- + 연산자를 사용한 문자열 연결
- f-string 사용하기
- Mutable value를 디폴트 매개변수로 사용
- 함수 호출할 때 해당 인자가 존재하지 않는다면 디폴트 매개변수를 사용하는데
- 이 때 mutable value가 사용된다면 각각 다른 함수의 사용에 같은 주솟값을 공유하게 되어
- 상태오염/보안결함 이 발생할 수 있음
- → None과 같은 immutable value로 설정하기
- import * 사용
전체적인 포인트를 보자면 결국 명시성, 효율성을 강조하는 것이라고 이해함
import 변수명, numpy 사용, 딕셔너리의 키/value 함수 활용등은 효율성을 강조하고
f-string 이나 파이썬 코드 가이드라인, 컴프리헨션 등은 또 명시성을 강조하는데
컴프리헨션은 효율성 뿐만 아니라 명시성 측면에서도 코드의 역할을 한눈에 보여준다는 점에서 중요한 기능인 것 같다
학부생때 배웠던 많은 지식들을 많이 활용하지 못하고 문제풀이에만 급급했던 것 같아서
이를 보완하고자 효율성 측면에서, 명시성 측면에서 더 발전된 코드를 짤 수 있도록 더 신경쓰고 노력해야할 것 같다.
'[데이터분석] 부트캠프 TIL' 카테고리의 다른 글
| 20260116 TIL (0) | 2026.01.16 |
|---|---|
| 20260115 TIL (1) | 2026.01.15 |
| 20260113 TIL (0) | 2026.01.13 |
| 20260112 TIL (1) | 2026.01.12 |
| 20260111 TIL (1) | 2026.01.12 |