Sparta/Theory

[250814] 스파르타코딩 본캠프 9일차 (1) - union, join

junecho 2025. 8. 14. 20:58

🟡 SQL 4차 강의 🟡

 

✅ UNION                                                                           

  • 테이블 수직결합. 즉, 위아래로 합친다
  • 컬럼 개수, 순서, 데이터 타입이 같아야 함
  • 2개 이상 테이블도 결합 가능
SELECT 컬럼1, 컬럼2, 컬럼3
FROM 테이블명1
UNION  
SELECT 컬럼1, 컬럼2, 컬럼3
FROM 테이블명2;

 

🔰 UNION / UNION ALL                                                                                   

 

 

 

 

✅ JOIN                                                                              

-- 공통 컬럼 1개일 때 작성법 --

SELECT *
FROM 테이블 AS a
JOIN 테이블 AS b
  ON a.공통컬럼 = b.공통컬럼;
-- 공통 컬럼 2개 이상일 때 작성법 --

SELECT *
FROM 테이블 AS a
JOIN 테이블 AS b  -- JOIN 종류: INNER, LEFT, RIGHT 등 지정
    ON a.공통컬럼1 = b.공통컬럼1
   AND a.공통컬럼2 = b.공통컬럼2;
  1. 공통 컬럼 찾기 - 공통 컬럼이 없다면 join 불가 / 공통 컬럼의 이름이 달라도 조인 가능
  2. 공통 컬럼 관계 찾기

  • PK(기본키)와 FK(외래키)는 다른 테이블을 연결하기 위해 사용되는 “고리” 같은 역할
  • 테이블A : 나는 이름컬럼과 나이컬럼이 있어 + 내 이름컬럼이 기준이야! (PK)
  • 테이블B : 나는 이름컬럼과 나이컬럼과 국가컬럼이 있어 + 내 이름컬럼은 테이블A 이름컬럼을 참조할꺼야 (FK)

이러한 관계들은 데이터 분석가가 설정하는 것이 아닌, 데이터 수집/저장 단계에서 정해짐

더보기
더보기
  • PK(기본키)와 FK(외래키)는 데이터 설계 단계에서 데이터베이스 관리자(DBA)나 개발자가 미리 정의합니다.
  • 이건 데이터가 수집·저장될 때부터 구조(스키마)에 포함돼 있어요.
  • 분석가가 임의로 PK/FK를 바꾸면, 다른 시스템이나 애플리케이션 동작이 깨질 수 있기 때문에 분석가가 설정하지 않습니다.

▼ 분석가의 역할  

  • 이미 정해진 PK/FK 관계를 이해하고, 그걸 JOIN 조건에 활용합니다.
  • PK/FK 관계를 알면
    • 어떤 테이블이 기준(주인, PK)인지
    • 어떤 테이블이 종속(손님, FK)인지
    • 어떤 방식으로 테이블을 합쳐야 데이터가 중복되거나 누락되지 않는지를 쉽게 파악할 수 있습니다.

 

 

🔰 ERD (Entity Relationship Diagram) : ERD 기호들을 통해서, 각 테이블이 어떻게 대응되는지 파악       

 

 1개정확히 1개차이는?

  • ✅ 1개 (One)
    • 일반적인 1개를 의미하지만, 제약은 느슨합니다.
    • 관계상 일반적으로 1개의 대상과 연결되지만, 실제 데이터에서는 없을 수도 있음 (nullable)
    • 예시)
      • 대부분 사람은 휴대폰 번호가 1개 있어요.
      • 하지만 번호 없는 사람도 있을 수 있죠! (노인, 일부 외국인 등)
    ✅ 정확히 1개 (One and only one)
    • 정말로 반드시 하나여야 하고, 빠짐없이 있어야 합니다.
    • DB에서 NOT NULL + UNIQUE 조건이 걸려 있다고 이해하면 돼요.
    • 예시)
      • 주민등록번호는 정확히 1개여야 한다. → 절대 없어도 안 되고, 중복도 안 됨

 

 

3. 적절한 조인 방식 찾기

https://sql-joins.leopard.in.ua/

 

 

 

 

🔰 INNER JOIN                                                                                        

두 테이블 다 만족하는 경우를 찾는다

select *
from s1 as a inner join s2 as b on a.name = b.name

s1.name = s2.name 이 일치하는 경우 두 테이블에서 일치하는값을 가진 데이터가 조회됨

 

 

 

🔰 LEFT JOIN                                                                                         

왼쪽에 테이블은 가만히 있고, 오른쪽에 있는 테이블을 갖다 붙인다!

select *
from s1 as a left join s2 as b on a.name = b.name

 

=> Why? s2 테이블의 Winfred가 없지??

  • a.name = b.name 조건 때문
  • s1 테이블(기준 테이블)에는 Winfred가 없음. s1이 기준이기 때문에 s1에 없는 이름은 가져올 수 없음

 

 

 

🔰 RIGHT JOIN                                                                                       

오른쪽에 테이블은 가만히 있고, 왼쪽에 있는 테이블을 갖다 붙인다!

select *
from s1 as a right join s2 as b on a.name = b.name

 

 

 

 

 

🔰 FULL OUTER JOIN                                                                         

  • 테이블의 모든 데이터를 보고 싶을 때 사용하는 JOIN
  • MySQL 환경에서는 FULL OUTER JOIN 지원 X
  • FULL OUTER JOIN = LEFT JOIN + UNION + RIGHT JOIN 으로 표현 가능
select *
from s1 as a left join s2 as b on a.name = b.name
union
select *
from s1 as a right join s2 as b on a.name = b.name

 

 


   과제   

더보기
더보기

1)

select a.name, a.age, b.goods_nm, b.goods_pay_date
from s1 a inner join 
(
	select name, goods_nm, max(goods_pay_date) as goods_pay_date
	from s2
	group by 1,2
) b on a.name = b.name

 

 

2)

select a.gb, count(distinct a.game_account_id) as usercnt
from
(
	select u.game_account_id, p.pay_amount, 
		case
			when p.pay_amount > 0 then '결제함'
			else '결제안함'
		end as gb
	from users u left join (
		select pay_amount, game_account_id 
		from payment
		) p on u.game_account_id = p.game_account_id 
	order by p.pay_amount
) a
group by a.gb

 

 

 

   프로그래머스 숙제   

더보기
더보기

 

https://school.programmers.co.kr/learn/courses/30/lessons/59044

SELECT ai.name, ai.datetime
from animal_ins ai left join animal_outs ao on ai.animal_id = ao.animal_id
where ao.datetime is null
order by ai.datetime limit 3

 

 

https://school.programmers.co.kr/learn/courses/30/lessons/164668

SELECT ub.writer_id as user_id, uu.nickname, sum(ub.price) as total_sales
from used_goods_board ub left join used_goods_user uu on ub.writer_id = uu.user_id
where ub.status = 'DONE'
group by uu.nickname
having total_sales >= 700000
order by total_sales

 

 

https://school.programmers.co.kr/learn/courses/30/lessons/59045

select a.animal_id, a.animal_type, a.name
from (
    SELECT ai.animal_id, ai.animal_type, ai.name, ai.sex_upon_intake, ao.sex_upon_outcome, 
           ai.sex_upon_intake != ao.sex_upon_outcome as new_sex_upon
    from animal_ins ai left join animal_outs ao on ai.animal_id = ao.animal_id
) a
where a.new_sex_upon = 1