카테고리 없음

TIL_20250508 (목) SQL 실전 DB 연습

elya0919 2025. 5. 8. 17:52
Lv1. 데이터 속 김서방 찾기

문제

본격적으로 시작해 볼까요?
상황: 여러분들은 스파르타코딩클럽의 분석가로 취직했습니다. DBeaver를 테스트 해볼 겸 “김”씨로 시작하는 이용자들 수를 세어 보기로 했습니다.
데이터 설명
user 테이블은 스파르타 코딩클럽에 가입한 유저들의 정보를 날짜별로 기록한 테이블입니다.
user_id: 익명화된 유저들의 아이디(varchar255)
created_at: 아이디 생성 날짜(timestamp)
updated_at: 정보 업데이트 날짜(timestamp)
name: 익명화된 유저들의 이름(varchar255)
email: 이메일(varchar255)
문제: 다음과 같은 결과테이블을 만들어봅시다.
name_cnt: “김”씨 성을 가지고 있는 교육생의 수
 
name_cnt: “김”씨 성을 가지고 있는 교육생의 수

select COUNT(name) 
from users
where name like '김%'

이렇게 풀었는데 결과 값은 정답과 같지만 문제점이 있었다.

****************************************

만약 동일한 user_id가 여러 줄에 걸쳐 등장하거나,
한 사람이 여러 번 등록된 경우에는 틀릴 수 있다.

그래서 실무에서는 항상 DISTINCT + 고유 식별자(user_id) 쓰는 게 더 안전한 습관
+
like(간단한 상황에는 좋음) 보다는 substr을 사용해 찾는게 처리범위도 적어 속도면에서 더 빠를 수 있다.

****************************************

그래서 새로 쓰면

select count(distinct user_id) as name_count
from users
where substr(name,1,1) = '김'

 

 

 

 

Lv2. 날짜별 획득포인트 조회하기

 

문제

상황: 이번에는 이용자들이 잘 활동하고 있는지 보고자 합니다. 포인트가 많을수록 활동을 잘하고 있다고 생각 할 수 있습니다. 날짜별로 획득한 포인트가 점점 늘어나는지 줄어드는지 확인해 봅시다.
데이터 설명
point_users 테이블은 스파르타코딩클럽 가입 유저들의 포인트에 대한 정보를 기록한 테이블입니다.
point_user_id: user_point 행을 구별하기 위한 key(varchar255)
created_at: 아이디 생성 날짜(timestamp)
updated_at: 정보 업데이트 날짜(timestamp)
user_id: 익명화된 유저들의 아이디(varchar255)
point: 보유하고 있는 포인트(int)
 
문제: 다음과 같은 결과테이블을 만들어봅시다.
created_at: 익명화된 유저들의 아이디(varchar255)
average_points: 유저가 획득한 날짜별 평균 포인트(int), 반올림 필수
 
SELECT date(created_at), round (AVG(point)) as point_avg
from point_users
group by 1

***

DATE 함수를 이용하면 TIMESTAMP 형식의 데이터를 날짜 형태로 변형할 수 있다.

***

 

 

 

Lv3. 이용자의 포인트 조회하기

 

문제

본격적으로 시작해 볼까요?
상황: 이번에는 이용자들 별로 획득한 포인트를 학생들에게 이메일로 보내려고 합니다. 이를 위한 자료를 가공해봅시다. 특히 users 테이블에는 있으나 point_users 에는 없는 유저가 있어요. 이 유저들의 경우 point를 0으로 처리합시다.
데이터 설명
users 테이블은 스파르타 코딩클럽에 가입한 유저들의 정보를 날짜별로 기록한 테이블입니다.
user_id: 익명화된 유저들의 아이디(varchar255)
created_at: 아이디 생성 날짜(timestamp)
updated_at: 정보 업데이트 날짜(timestamp)
name: 익명화된 유저들의 이름(varchar255)
email: 이메일(varchar255)
point_users 테이블은 스파르타코딩클럽 가입 유저들의 포인트에 대한 정보를 기록한 테이블입니다.
point_user_id: point_users 테이블의 행을 구별하기 위한 key(varchar255)
created_at: 아이디 생성 날짜(timestamp)
updated_at: 정보 업데이트 날짜(timestamp)
user_id: 익명화된 유저들의 아이디(varchar255)
point: 보유하고 있는 포인트(int)
 
문제: 다음과 같은 결과 테이블을 만들어봅시다.
user_id: 익명화된 유저들의 아이디
email: 유저들의 이메일
point: 유저가 획득한 포인트
users 테이블에는 있지만 point_users에는 없는 user는 포인트가 없으므로 0 으로 처리
포인트 기준으로 내림차순 정렬
 
1~10행
490 ~ 498행

 

SELECT u.user_id, u.email, ifnull(p.point,0) as point
from users u
left join point_users p on p.user_id = u.user_id
order by p.point desc

*** 

처음에 if ( p.point = null, 0, p.point )라고 쿼리를 작성했는데
null 값은 비교 연산자를 사용 x 
그래서 if null or coalesce 사용 

***

 

Lv4. 단골 고객님 찾기

문제:

Orders 테이블:
OrderID
CustomerID
OrderDate
TotalAmount
101
1
2024-01-01
150
102
2
2024-01-03
200
103
1
2024-01-04
300
104
3
2024-01-04
50
105
2
2024-01-05
80
106
4
2024-01-06
400
Customers 테이블:
CustomerID
CustomerName
Country
1
Alice
USA
2
Bob
UK
3
Charlie
USA
4
David
Canada

요구사항:

1.
고객별로 주문 건수와 총 주문 금액을 조회하는 SQL 쿼리를 작성해주세요.
a.
출력 결과에는 고객 이름, 주문 건수, 총 주문 금액이 포함되어야 합니다. 단, 주문을 한 적이 없는 고객도 결과에 포함되어야 합니다.
b.
기대결과
CustomerName
OrderCount
TotalSpent
Alice
2
450
Bob
2
280
Charlie
1
50
David
1
400
SELECT 
c.CustomerName,
count(o.OrderID) as orderCount,
sum(o.TotalAmount) as TotalSpent
from p4_orders_table o
join p4_customers_table c on o.CustomerID = c.CustomerID
group by c.CustomerName

*** 
처음에 위에 쿼리를 작성
문제에 주문한 적이 없는 고객 
조회 -> left join
주문 x -> 즉, null 값일테니 0으로 반환 
***

SELECT 
c.CustomerName,
count(o.OrderID) as orderCount,
ifnull(sum(o.TotalAmount),0) as TotalSpent
from p4_orders_table o
left join p4_customers_table c on o.CustomerID = c.CustomerID
group by c.CustomerName

 

 

 

2.
나라별로 총 주문 금액이 가장 높은 고객의 이름과 그 고객의 총 주문 금액을 조회하는 SQL 쿼리를 작성해주세요.
a.
기대결과
Country
Top_Customer
Top_Spent
USA
Alice
450
UK
Bob
280
Canada
David
400

제약사항:

두 쿼리 모두 서브쿼리, JOIN, GROUP BY, HAVING 등을 사용해 풀 수 있어야 한다.
주문을 한 적이 없는 고객도 첫 번째 쿼리 결과에 포함되어야 한다.
SELECT 
c.Country, c.CustomerName as Top_customer, sum(o.totalamount) as Total_Spent 
from p4_orders_table o
join p4_customers_table c on o.CustomerID = c.CustomerID
group by c.Country,c.CustomerName
Having 
	sum(o.totalamount) = (
		select max(SumSpent)
		from (
			select sum(o2.totalamount) as SumSpent
			from p4_orders_table o2
			join p4_customers_table c2 on o2.CustomerID = c2.CustomerID
			where c2.Country = c.Country 
			group by c2.CustomerID
			) as t 
			)

 

나라별로 총 주문 금액이 가장 높은 고객의 이름과 그 고객의 총 주문 금액을 조회하는 SQL 쿼리를 작성해주세요.

실행 순서 요약

단계설명
FROM + JOIN으로 고객별 주문 목록 완성
GROUP BY로 고객별 합계 계산
HAVING절의 서브쿼리가 각 Country마다 실행
그 Country 내에서 최고 총합만 남김 (조건 만족한 고객만 남음)
SELECT로 최종 결과 출력

HAVING절은 파이썬의 for문과 비슷한 개념으로 생각하니 이해가 간다.

조건을 만들어놓고 나라별로 대입되며 조건에 맞는 값만 필터링한다.