์ŠคํŒŒ๋ฅดํƒ€ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„(25.12.01~)

์ŠคํŒŒ๋ฅดํƒ€ ๋‚ด์ผ๋ฐฐ์›€์บ ํ”„_๋ณธ์บ ํ”„_data11๊ธฐ ๊น€์„ ์˜_TIL_Day 6

0๏ธโƒฃ 2025. 12. 30. 23:11

<์˜ค๋Š˜์˜ ํ•™์Šต>

  • SQL ๋ผ์ด๋ธŒ์„ธ์…˜ 5ํšŒ์ฐจ (CASE, โญ๏ธ์„œ๋ธŒ์ฟผ๋ฆฌ, โญ๏ธCTE)

<ํ•™์Šต๋‚ด์šฉ ์ •๋ฆฌ>

# SQL ๋ผ์ด๋ธŒ ์„ธ์…˜ 5ํšŒ์ฐจ

1.  CASE

๋‘ ๊ฐ€์ง€ ์ผ€์ด์Šค ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์Œ. ํ‘œ๊ธฐ์˜ ์ฐจ์ด์ผ ๋ฟ.

else: ์กฐ๊ฑด ์™ธ ๋‹ค๋ฅธ ๋ณ€์ˆ˜์˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์ง€์ •ํ•ด์ฃผ๋Š” ๊ฒƒ. ์—๋Ÿฌ ๋ฐฉ์ง€์— ์ค‘์š”ํ•จ!

--(A) ๊ฐ’ ๋น„๊ตํ˜•(Simple CASE)
SELECT
  student_id,
  student_name,
  region,
CASE region
	WHEN 'SEOUL' THEN '์„œ์šธ'
	WHEN 'BUSAN' THEN '๋ถ€์‚ฐ'
	ELSE '๊ธฐํƒ€'
	END AS region_kor
FROM basic.students
ORDER BY student_id;

--(B) ์กฐ๊ฑด์‹ํ˜•(Searched CASE)
SELECT
  student_id,
  student_name,
  region,
CASE
	WHEN region = 'SEOUL' THEN '์„œ์šธ'
	WHEN region = 'BUSAN' THEN '๋ถ€์‚ฐ'
	ELSE '๊ธฐํƒ€'
	END AS region_kor
FROM basic.students
ORDER BY student_id;
  • case ๋‚ด / count ๋กœ null์ธ ํ–‰ ๊ฐœ์ˆ˜
--SUM์œผ๋กœ Null ๊ฐœ์ˆ˜ ์นด์šดํŠธ
--ํ•ด๋‹น ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” null ํ–‰์„ 1๋กœ ๋ฐ˜ํ™˜, ๋ชจ๋“  1์„ ๋”ํ•˜๋ฉด ํ–‰์˜ ๊ฐœ์ˆ˜
SELECT
COUNT(*)AS total_enrollments,
SUM(CASE WHEN coupon_code IS NOT NULL THEN 1 ELSE 0 END)AS coupon_used_cnt,
SUM(CASE WHEN coupon_code IS NULL THEN 1 ELSE 0 END)AS no_coupon_cnt
FROM basic.enrollments;

--0์ด ๋ฐ˜ํ™˜๋œ ํ–‰๊นŒ์ง€ ๋ชจ๋‘ ์นด์šดํŠธ, count(*)์™€ ๋™์ผํ•œ ๊ฐ’๋งŒ ๋‚˜์˜ด.
SELECT
COUNT(*)AS total_enrollments,
COUNT(CASE WHEN coupon_code IS NOT NULL THEN 1 ELSE 0 END)AS coupon_used_cnt,
COUNT(CASE WHEN coupon_code IS NULL THEN 1 ELSE 0 END)AS no_coupon_cnt
FROM basic.enrollments;

 

2. โญ๏ธ์„œ๋ธŒ์ฟผ๋ฆฌ

:๋‹ค๋ฅธ SQL ์•ˆ์— ๋“ค์–ด์žˆ๋Š” SELECT

https://tjsdud7032.tistory.com/34

 

[๊ฐœ๋…์ •๋ฆฌ] ์„œ๋ธŒ์ฟผ๋ฆฌ(Subquery)

๋‹ค๋ฅธ SQL ์•ˆ์— ๋“ค์–ด์žˆ๋Š” SELECTMySQL์€ ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ˜•ํƒœ๊ฐ€ 4์ข…๋ฅ˜scalar(๊ฐ’ 1๊ฐœ)row(ํ–‰ 1๊ฐœ)column(์—ด 1๊ฐœ = ๋ฆฌ์ŠคํŠธ)table(ํ‘œ)Q. ํ‰๊ท ๋ณด๋‹ค ๋น„์‹ผ ๊ฐ•์ขŒ ์ฐพ๊ธฐ(1. ์„œ๋ธŒ ์ฟผ๋ฆฌ)๋ชจ๋“  ๊ฐ•์ขŒ ํ‰๊ท  ๊ตฌํ•˜๊ธฐ (2. ๋ฐ”๊นฅ

tjsdud7032.tistory.com

๋ฏธ๋‹ˆ์‹ค์Šต 4) Scalar Subquery; ๊ฐ’ 1๊ฐœ

๋ฌธ์ œ: enrollments์—์„œ final_price๊ฐ€ “์ „์ฒด ํ‰๊ท  final_price”๋ณด๋‹ค ํฐ ์‹ ์ฒญ๋งŒ ๋ณด๊ธฐ

์ถœ๋ ฅ: enrollment_id, final_price

-- ์ •๋‹ต
SELECT enrollment_id, final_price
FROM basic.enrollments
WHERE final_price > (
	-- ์ „์ฒด ํ‰๊ท 
	SELECT avg(final_price)
	FROM basic.enrollments
	);

๋ฏธ๋‹ˆ์‹ค์Šต 5) Column Subquery; ์—ด1๊ฐœ, ๋ฆฌ์ŠคํŠธ
IN()

๋ฌธ์ œ: level='beginner'์ธ ๊ฐ•์ขŒ๋ฅผ ์‹ ์ฒญํ•œ enrollments๋งŒ ์ถœ๋ ฅ

์ถœ๋ ฅ: enrollment_id, course_id

--์ •๋‹ต
SELECT enrollment_id, course_id
FROM basic.enrollments
where course_id IN (
	SELECT course_id
	FROM basic.courses
	WHERE level = 'beginner'
	);

๋ฏธ๋‹ˆ์‹ค์Šต 6) Table Subquery; / ํ‘œ
EXISTS / NOT EXISTS

๋ฌธ์ œ: “๊ฒฐ์ œ ํ…Œ์ด๋ธ”(payments)์— ๊ธฐ๋ก์ด ํ•œ ๋ฒˆ๋„ ์—†๋Š” ์‹ ์ฒญ(enrollment)” ์ฐพ๊ธฐ
์ถœ๋ ฅ: enrollment_id

-- ์ •๋‹ต
SELECT e.enrollment_id
FROM basic.enrollments e 
where not exists (
	select *
	from basic.payments p
	where p.enrollment_id=e.enrollment_id
	);

๋ฏธ๋‹ˆ์‹ค์Šต 7) FROM ์„œ๋ธŒ์ฟผ๋ฆฌ(ํŒŒ์ƒ ํ…Œ์ด๋ธ”)

๋ฌธ์ œ: ํ•™์ƒ๋ณ„ ์‹ ์ฒญ ๊ฑด์ˆ˜(enroll_cnt)๋ฅผ students์— ๋ถ™์—ฌ์„œ ์ถœ๋ ฅ

์ถœ๋ ฅ: student_id, student_name, enroll_cnt (์‹ ์ฒญ ์—†์œผ๋ฉด 0)

-- ํ•™์ƒ๋ณ„
select s.student_id,
       s.student_name,
       ifnull(enr.enroll_cnt, 0) as enroll_cnt
from basic.students s
	left join
		(-- ํ•™์ƒ๋ณ„ ์‹ ์ฒญ๊ฑด์ˆ˜
		select student_id,
		       count(enrollment_id) as enroll_cnt
		from basic.enrollments
		group by student_id
		)as enr
	on s.student_id=enr.student_id;

๋ฏธ๋‹ˆ์‹ค์Šต 8) CTE (WITH) : ์ด๋ฆ„ ๋ถ™์ธ ํŒŒ์ƒํ…Œ์ด๋ธ”

๋ฌธ์ œ: is_active = 1์ธ ๊ฐ•์ขŒ๋งŒ ๋ฝ‘๋Š” CTE(active_courses)๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ CTE๋ฅผ ์กฐํšŒํ•˜์„ธ์š”.

์ถœ๋ ฅ: course_id, course_name, is_active

with active_course as (
	select course_id, course_name, is_active
	from basic.courses
	where is_active = 1
	)
select *
from active_course;

 

 

  ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ ์šฉ๋„๋ฅผ ์ž˜ ์ฒดํฌ!  

  ํ•˜๋‚˜์˜ ๊ฐ’๊ณผ ๋น„๊ต = Scalar  

  ์—ฌ๋Ÿฌ ๊ฐ’๊ณผ ๋น„๊ต = Column(IN())  

  ์žˆ๋ƒ, ์—†๋ƒ ํ™•์ธ = Table(exists, not exists)  

  ์ค‘๊ฐ„๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ = FROM  

 

3. ์ข…ํ•ฉ์‹ค์Šต
ใ…ใ…Š.. ๋งž์ท„๋‹ค ใ…ใ…Šใ…ใ…Šใ…ใ…Š (๊ทผ๋ฐ 40๋ถ„ ๊ฑธ๋ฆผใ…‹)

โœ… ์ตœ์ข… ๋ฏธ์…˜: “ํ•™์ƒ ํ•œ ์ค„ ์š”์•ฝ ๋ฆฌํฌํŠธ”
     ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค ๊ฒฐ๊ณผ(ํ•™์ƒ 1๋ช… = 1ํ–‰)
์ถœ๋ ฅ:
- `student_id, student_name, region, segment`
- `enroll_cnt` : ์‹ ์ฒญ ๊ฑด์ˆ˜ 
- `coupon_used_cnt` : ์ฟ ํฐ ์“ด ์‹ ์ฒญ ๊ฑด์ˆ˜
- `coupon_user_flag` : CASE๋กœ ๋ผ๋ฒจ
    - coupon_used_cnt = 0 → `no_coupon_user`
    - 1 ์ด์ƒ → `coupon_user`

-- ํ•™์ƒ๋ณ„ ์‹ ์ฒญ๊ฑด์ˆ˜ enrollments
WITH
enr_by_stu AS (
	SELECT student_id,
       count(*) AS enroll_cnt
	FROM basic.enrollments
	GROUP BY student_id
	),
-- ํ•™์ƒ๋ณ„ ์ฟ ํฐ ์“ด ์‹ ์ฒญ ๊ฑด์ˆ˜ enrollments
cp_cnt_per_stu AS (
	SELECT student_id,
	       SUM(CASE WHEN coupon_code IS NULL THEN 0
	       		    ELSE 1 end) AS coupon_cnt
	FROM basic.enrollments e
	GROUP BY student_id
	)
-- ์ตœ์ข…์ถœ๋ ฅ
SELECT s.student_id,
	   s.student_name,
	   s.region,
	   s.segment,
	   IFNULL(e.enroll_cnt, 0) AS enroll_cnt, -- ์‹ ์ฒญ๊ฑด์ˆ˜
	   IFNULL(c.coupon_cnt, 0) AS coupon_used_cnt, -- ์ฟ ํฐ ์‚ฌ์šฉ ์ˆ˜
	   CASE WHEN c.coupon_cnt = 0 THEN 'no_coupon_user'
	        ELSE 'coupon_user'
	        END AS coupon_user_flag
FROM basic.students s
	LEFT JOIN enr_by_stu e
	ON s.student_id = e.student_id
	LEFT JOIN cp_cnt_per_stu c
	ON s.student_id = c.student_id
ORDER BY s.student_id;

SQL ๋ฐ์ผ๋ฆฌ ํ€˜์ŠคํŠธ
# ๊ณผ์ œ

๊ณผ์ œ1) CASE๋กœ “์ฟ ํฐ ์‚ฌ์šฉ ์—ฌ๋ถ€ + ๊ฐ€๊ฒฉ ๊ตฌ๊ฐ„” ๋ผ๋ฒจ ๋งŒ๋“ค๊ธฐ

๋”๋ณด๊ธฐ

์ƒํ™ฉ: ์šด์˜ํŒ€์ด `enrollments`๋ฅผ ๋ณผ ๋•Œ, ์ฟ ํฐ ์‚ฌ์šฉ ์—ฌ๋ถ€์™€ ๊ฒฐ์ œ๊ธˆ์•ก ๊ตฌ๊ฐ„์ด ํ•œ๋ˆˆ์— ๋ณด์ด๊ธธ ์›ํ•ฉ๋‹ˆ๋‹ค.

 

๋ชฉํ‘œ: `enrollment_status`๊ฐ€ `active`, `completed`์ธ ์‹ ์ฒญ๋งŒ ๋Œ€์ƒ์œผ๋กœ ์•„๋ž˜ ์ปฌ๋Ÿผ์„ ์ถœ๋ ฅํ•˜์„ธ์š”.

 

์ถœ๋ ฅ ์ปฌ๋Ÿผ

- `enrollment_id`

- `student_id`

- `final_price`

- `coupon_flag`

      - ์ฟ ํฐ ๋ฏธ์‚ฌ์šฉ(`coupon_code IS NULL`) → `'no_coupon'`

      - ์ฟ ํฐ ์‚ฌ์šฉ → `'coupon_used'`

- `price_bucket`

     - `final_price < 50000` → `'low'`

     - `50000 <= final_price < 90000` → `'mid'`

     - `final_price >= 90000` → `'high'`

 

์ •๋ ฌ

`enrollment_id` ์˜ค๋ฆ„์ฐจ์ˆœ

-- ๐Ÿ“Œ์˜ค๋‹ต
SELECT enrollment_id,
       student_id,
       final_price,
       -- ์ฟ ํฐ ์‚ฌ์šฉ ์—ฌ๋ถ€
       CASE WHEN coupon_code IS NULL THEN 'no_coupon'
            ELSE 'coupon_used'
           END AS coupon_flag,
       -- price_bucket
       CASE WHEN final_price < 50000 THEN 'low'
            WHEN 50000 <= final_price < 90000 THEN 'mid'
            WHEN final_price >= 90000 THEN 'high'
           END price_bucket
FROM basic.enrollments
WHERE enrollment_status IN ('active', 'completed')
ORDER BY enrollment_id ASC;

-- ๐Ÿ’กCASE WHEN ๋†’->๋‚ฎ
SELECT enrollment_id,
       student_id,
       final_price,
       -- ์ฟ ํฐ ์‚ฌ์šฉ ์—ฌ๋ถ€
       CASE WHEN coupon_code IS NULL THEN 'no_coupon'
            ELSE 'coupon_used'
           END AS coupon_flag,
       -- price_bucket
       CASE WHEN final_price >= 90000 THEN 'high'
            WHEN 50000 <= final_price < 90000 THEN 'mid'
	        WHEN final_price < 50000 THEN 'low'
           END AS price_bucket
FROM basic.enrollments
WHERE enrollment_status IN ('active', 'completed')
ORDER BY enrollment_id ASC;

-- ๐Ÿ’กCASE WHEN 'mid' ๋ถ€๋ถ„ ๋‚˜๋ˆ ์„œ ์“ฐ๊ธฐ
SELECT enrollment_id,
       student_id,
       final_price,
       -- ์ฟ ํฐ ์‚ฌ์šฉ ์—ฌ๋ถ€
       CASE WHEN coupon_code IS NULL THEN 'no_coupon'
            ELSE 'coupon_used'
           END AS coupon_flag,
       -- price_bucket
       CASE WHEN final_price < 50000 THEN 'low'
            WHEN final_price >= 50000 AND final_price < 90000 THEN 'mid'
	        WHEN final_price >= 90000 THEN 'high'
           END AS price_bucket
FROM basic.enrollments
WHERE enrollment_status IN ('active', 'completed')
ORDER BY enrollment_id ASC;
<์˜ค๋‹ต๋…ธํŠธ>
- CASE WHEN ๋ฒ”์œ„์กฐ๊ฑด ์ ์„ ๋•Œ, ๋‚ฎ์€๊ฒƒ๋ถ€ํ„ฐ ๋†’์€ ๊ฒƒ๊นŒ์ง€ ์“ฐ๊ณ  ์ค‘๊ฐ„ ๋ฒ”์œ„๋ฅผ ๋ฌถ์–ด์„œ (1<x<=10) ์“ฐ๋ฉด ๊ฐ’์— ์˜ค๋ฅ˜๊ฐ€ ๋‚  ์ˆ˜ ์žˆ๋‹ค.
   ์™œ? x์˜ ์กฐ๊ฑด์„ ๋งจ์œ„ ์กฐ๊ฑด๋ถ€ํ„ฐ ํ›‘์„ ๋•Œ, ์ฒซ ์ค„ ์กฐ๊ฑด์— ๋งŒ์กฑํ•˜๋ฉด ์•„๋ž˜ ์กฐ๊ฑด์€ ๊ฒ€์‚ฌ์กฐ์ฐจ ์•ˆ ๋จ.
๋ฐฉ๋ฒ•1) ๊ฐ’์ด ๋†’์€ ์กฐ๊ฑด์„ ๋งจ ์œ„๋กœ -> ๋‚ฎ์€ ๊ฐ’ ์กฐ๊ฑด
๋ฐฉ๋ฒ•2) ์ค‘๊ฐ„๋ฒ”์œ„ ์กฐ๊ฑด์„ ๋ฌถ์–ด์„œ ์“ฐ์ง€ ๋ง๊ณ  ๋‚˜๋ˆ ์„œ (WHEN x>1 AND x<=10)

 

๊ณผ์ œ2) IN ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ “SQL ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐ•์ขŒ๋ฅผ ์‹ ์ฒญํ•œ ํ•™์ƒ” ์ฐพ๊ธฐ

๋”๋ณด๊ธฐ

์ƒํ™ฉ: ๋งˆ์ผ€ํŒ…ํŒ€์ด **SQL ์นดํ…Œ๊ณ ๋ฆฌ** ๊ฐ•์ขŒ๋ฅผ ์‹ ์ฒญํ•œ ํ•™์ƒ์—๊ฒŒ๋งŒ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋ ค ํ•ฉ๋‹ˆ๋‹ค.

๋ชฉํ‘œ: `courses.category = 'sql'`์ธ ๊ฐ•์ขŒ๋ฅผ **ํ•œ ๋ฒˆ์ด๋ผ๋„ ์‹ ์ฒญํ•œ** ํ•™์ƒ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•˜์„ธ์š”.
(์‹ ์ฒญ ์ƒํƒœ๋Š” `active`, `completed`๋งŒ ํฌํ•จ / `cancelled` ์ œ์™ธ)

์ถœ๋ ฅ ์ปฌ๋Ÿผ:
- `student_id`
- `student_name`

์ •๋ ฌ:

- `student_id` ์˜ค๋ฆ„์ฐจ์ˆœ

-- ๐Ÿ“Œ์˜ค๋‹ต / ์ ‘๊ทผ๋ฐฉ์‹ ํ‹€๋ ธ์Œ.
SELECT student_id,
       student_name
FROM basic.students
WHERE student_id IN (
	SELECT e.student_id
	FROM basic.enrollments e
	WHERE e.enrollment_status IN ('active', 'completed')
	)
ORDER BY student_id;

-- ๐Ÿ’ก์กฐ๊ฑด ๋‘ ๊ฐœ join์œผ๋กœ ํ•ฉ์น˜๊ธฐ
SELECT s.student_id, s.student_name 
FROM basic.students s
WHERE s.student_id IN (
	SELECT e.student_id
	FROM basic.enrollments e
		LEFT JOIN basic.courses c
		ON e.course_id=c.course_id
	WHERE c.category = 'sql'
	AND e.enrollment_status IN ('active', 'completed')
	)
ORDER BY s.student_id ASC;

-- ๐Ÿ’ก๋‹ต์ง€ ์ •๋‹ต
SELECT s.student_id,
       s.student_name
FROM basic.students s
WHERE s.student_id IN (
  SELECT e.student_id
  FROM basic.enrollments e
  -- inrollment ์กฐ๊ฑด ๋‹ฌ๊ธฐ
  WHERE e.enrollment_status IN ('active', 'completed')
    -- and๋กœ ์ถ”๊ฐ€ ์กฐ๊ฑด ๋‹ฌ๊ธฐ
    AND e.course_id IN (
      SELECT c.course_id
      FROM basic.courses c
      WHERE c.category = 'sql'
    )
)
ORDER BY s.student_id;

 

<์˜ค๋‹ต๋…ธํŠธ>
- ์„œ๋ธŒ์ฟผ๋ฆฌ(IN/EXISTS) ์•ˆ์—๋Š” ‘ID๋ฅผ ๊ณ ๋ฅด๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ์กฐ๊ฑด’์ด ๋“ค์–ด๊ฐ€์•ผ ํ•œ๋‹ค.
   ๋‘ ์กฐ๊ฑด์ด ๊ฐ๊ฐ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์— ์žˆ์œผ๋ฉด JOIN ์‚ฌ์šฉ

   courses ์กฐ๊ฑด, enrollments ์กฐ๊ฑด์„ join์œผ๋กœ ํ•ฉ์นจ
   ์ด๊ฒƒ์„ WHERE IN() ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ์‚ฌ์šฉ
1๏ธโƒฃ ๋จผ์ € ‘์–ด๋–ค ID๊ฐ€ ๋Œ€์ƒ์ธ์ง€’๋ฅผ ์ •์˜ํ•œ๋‹ค
2๏ธโƒฃ ๊ทธ ID๋ฅผ ๋ฐ”๊นฅ์—์„œ ์ถœ๋ ฅํ•œ๋‹ค

๊ณผ์ œ3) NOT EXISTS๋กœ “์ฟ ํฐ์„ ํ•œ ๋ฒˆ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ํ•™์ƒ” ์ฐพ๊ธฐ

๋”๋ณด๊ธฐ

์ƒํ™ฉ
์ฟ ํฐ์„ ํ•œ ๋ฒˆ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ํ•™์ƒ์—๊ฒŒ “์ฒซ ์ฟ ํฐ ํ˜œํƒ”์„ ์ฃผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๋ชฉํ‘œ
์•„๋ž˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ํ•™์ƒ๋งŒ ์ถœ๋ ฅํ•˜์„ธ์š”.
- ํ•ด๋‹น ํ•™์ƒ์˜ enrollments ์ค‘์—์„œ
- `coupon_code IS NOT NULL`์ธ ํ–‰์ด **๋‹จ ํ•œ ๊ฑด๋„ ์—†๋Š” ํ•™์ƒ**
> ํฌ์ธํŠธ: “์—†๋‹ค”๋ฅผ ์ฐพ๋Š” ๊ฐ€์žฅ ๋Œ€ํ‘œ ํŒจํ„ด์ด NOT EXISTS ์ž…๋‹ˆ๋‹ค.

์ถœ๋ ฅ ์ปฌ๋Ÿผ
- `student_id`
- `student_name`

์ •๋ ฌ
- `student_id` ์˜ค๋ฆ„์ฐจ์ˆœ

-- ์ •๋‹ต
SELECT s.student_id, s.student_name 
FROM basic.students s
WHERE NOT EXISTS (
	SELECT *
	FROM basic.enrollments e
	WHERE e.student_id=s.student_id
	AND e.coupon_code IS NOT NULL 
	)
ORDER BY s.student_id;

๊ณผ์ œ4) CTE๋กœ “ํ•™์ƒ๋ณ„ ์‹ ์ฒญ/์ฟ ํฐ ์š”์•ฝ + ๋ผ๋ฒจ( CASE )” ๋งŒ๋“ค๊ธฐ

๋”๋ณด๊ธฐ

์ƒํ™ฉ
์šด์˜ํŒ€์ด ํ•™์ƒ๋ณ„๋กœ “์‹ ์ฒญ ์ˆ˜ / ์ฟ ํฐ ์‚ฌ์šฉ ์ˆ˜ / ์ฟ ํฐ ์œ ์ € ์—ฌ๋ถ€ / ์‹ ์ฒญ ์œ ์ € ์—ฌ๋ถ€”๋ฅผ ํ•œ ๋ฒˆ์— ๋ณด๊ณ  ์‹ถ์–ดํ•ฉ๋‹ˆ๋‹ค.

๋ชฉํ‘œ
CTE 2๊ฐœ๋กœ ์š”์•ฝ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“  ๋’ค `students`์— LEFT JOINํ•ด์„œ ์•„๋ž˜๋ฅผ ์ถœ๋ ฅํ•˜์„ธ์š”.
๋‹จ, **์‹ ์ฒญ ์ƒํƒœ๋Š” `active`, `completed`๋งŒ ํฌํ•จ** (์ทจ์†Œ ์ œ์™ธ)

์ถœ๋ ฅ ์ปฌ๋Ÿผ
- `student_id`
- `student_name`
- `enroll_cnt` (์‹ ์ฒญ ์ˆ˜)
- `coupon_used_cnt` (์ฟ ํฐ ์‚ฌ์šฉ ์‹ ์ฒญ ์ˆ˜)
- `enroll_flag`
    - `enroll_cnt = 0` → `'no_enroll'`
    - ๊ทธ ์™ธ → `'has_enroll'`
- `coupon_user_flag`
    - `coupon_used_cnt = 0` → `'no_coupon_user'`
    - ๊ทธ ์™ธ → `'coupon_user'`
- `coupon_usage_rate_pct`
    - `enroll_cnt = 0`์ด๋ฉด `0`
    - ๊ทธ ์™ธ `ROUND(coupon_used_cnt / enroll_cnt * 100, 1)`

์ •๋ ฌ
- `student_id` ์˜ค๋ฆ„์ฐจ์ˆœ

-- ๐Ÿ“Œ์˜ค๋‹ต
WITH 
	-- ์‹ ์ฒญ ์ˆ˜
	enroll_cnt AS ( -- CTE์˜ ๋ณ„์นญ์€ ์„œ๋ธŒ์ฟผ๋ฆฌ์™€ ๋‹ค๋ฅด๊ฒŒ ๋ฐฐ์ •ํ•˜๋Š” ๊ฒŒ ์ข‹์Œ.
		SELECT e.student_id
			   , COUNT(*) -- ๋ณ„์นญ์„ ๊ผญ ์ ์–ด์ค˜์•ผ ํ•จ.
		FROM basic.enrollments e
		WHERE e.enrollment_status IN ('active', 'completed')
		GROUP BY e.student_id
		)
	-- ์ฟ ํฐ ์‚ฌ์šฉ ์ˆ˜
	cp_cnt AS (
		SELECT e.student_id
			   , SUM(CASE WHEN e.coupon_code IS NOT NULL THEN 1 ELSE 0 END)AS coupon_cnt
		FROM basic.enrollments e
		GROUP BY e.student_id
		)
-- ์ตœ์ข…์ถœ๋ ฅ(ํ•™์ƒ๋ณ„)
SELECT s.student_id
	   , s.student_name
	   , enroll_cnt
       , ifnull(e.enroll_cnt, 0) AS enroll_cnt
	   , ifnull(c.coupon_cnt, 0) AS coupon_cnt
	   -- enroll_flag
       , CASE WHEN enroll_cnt=0 THEN 'no_enroll' -- select์—์„œ ์‚ฌ์šฉํ•œ ๋ณ„์นญ์€ select ๋‚ด์—์„œ ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€!!!
          ELSE 'has_enroll'
          END enroll_flag
	   -- coupon_user_flag
       , CASE WHEN ifnull(c.coupon_cnt, 0)=0 THEN 'no_coupon_user'
          ELSE 'coupon_user'
          END coupon_user_flag
	   -- coupon_usage_rate_pct -- ๋ถ„๋ชจ๊ฐ€ 0์ผ ๋•Œ ์˜ค๋ฅ˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ ์žˆ์Œ. ๋ถ„๋ชจ๊ฐ€ 0์ผ ๋•Œ๋Š” ๊ทธ๋ƒฅ 0์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก.
FROM basic.students s
	LEFT JOIN enroll_cnt e
	ON s.student_id=e.student_id
    
-- ๐Ÿ’กํ•ด์„ค
WITH 
	-- ์‹ ์ฒญ ์ˆ˜
	enr_cnt AS (
		SELECT e.student_id
			   , COUNT(*) AS enroll_cnt
		FROM basic.enrollments e
		WHERE e.enrollment_status IN ('active', 'completed')
		GROUP BY e.student_id
		),
	-- ์ฟ ํฐ ์‚ฌ์šฉ ์ˆ˜
	cp_cnt AS (
		SELECT e.student_id
			   , SUM(CASE WHEN e.coupon_code IS NOT NULL THEN 1 ELSE 0 END)AS coupon_cnt
		FROM basic.enrollments e
		GROUP BY e.student_id
		)
-- ์ตœ์ข…์ถœ๋ ฅ(ํ•™์ƒ๋ณ„)
SELECT s.student_id
	   , s.student_name
	   , ifnull(e.enroll_cnt, 0) AS enroll_cnt
	   , ifnull(c.coupon_cnt, 0) AS coupon_cnt
	   -- enroll_flag
	   , CASE WHEN ifnull(e.enroll_cnt, 0)=0 THEN 'no_enroll'
	   		  ELSE 'has_enroll'
	   		  END enroll_flag
	   -- coupon_user_flag
	   , CASE WHEN ifnull(c.coupon_cnt, 0)=0 THEN 'no_coupon_user'
	   		  ELSE 'coupon_user'
	   		  END coupon_user_flag
	   -- coupon_usage_rate_pct
	   , CASE WHEN ifnull(e.enroll_cnt, 0)=0 THEN 0
	   		  ELSE round(ifnull(c.coupon_cnt, 0)/ifnull(e.enroll_cnt, 0)*100, 1)
	   		  END AS coupon_usage_rate_pct
FROM basic.students s
	LEFT JOIN enr_cnt e
	ON s.student_id=e.student_id
	LEFT JOIN cp_cnt c
	ON s.student_id=c.student_id
ORDER BY student_id ASC;
<์˜ค๋‹ต๋…ธํŠธ>
- SELECT ๋‚ด ๋ณ„์นญ์€ SELECT์—์„œ ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ

CASE WHEN
ifnull(e.enroll_cnt, 0)=0 THEN 0

           ELSE ROUND(ifnull(c.coupon_cnt, 0) / ifnull(e.enroll_cnt, 0) * 100, 1) END AS coupon_usage_rate_pct
- ๋‚˜๋ˆ„๊ธฐ์˜ ๋ถ„๋ชจ๊ฐ€ 0์ด๋ฉด ๊ณ„์‚ฐ ๋ถˆ๊ฐ€ → ์˜ค๋ฅ˜
- ๋ถ„๋ชจ๊ฐ€ 0์ด๋ฉด ๊ทธ๋Œ€๋กœ 0์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•จ โ–ถ ๊ณ„์‚ฐ ์ž์ฒด๋ฅผ ๊ฑด๋„ˆ๋œ€.
- ELSE: ๋ถ„๋ชจ๊ฐ€ 0์ด ์•„๋‹Œ ๋ชจ๋“  ๊ฒฝ์šฐ๋Š” ์ด๋ ‡๊ฒŒ ๊ณ„์‚ฐํ•ด๋ผ.

WITH coupon_by_student AS (
          SELECT student_id,
                          COUNT(*) AS coupon_used_cnt
          FROM basic.enrollments
          WHERE enrollment_status IN ('active', 'completed')
          AND coupon_code IS NOT NULL
          GROUP BY student_id
          )
- coupon_code๊ฐ€ NULL์ธ ๊ฒƒ์„ ์ œ์™ธํ•œ ๊ฐœ์ˆ˜๋ฅผ ์„ธ์•ผํ•  ๋•Œ SUM๋„ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ,
   ์• ์ดˆ์— WHERE์—์„œ ๊ฑฐ๋ฅด๋Š” ๊ฒŒ ๋” ๊ฐ„๋‹จ!!

# ํ€˜์ŠคํŠธ

Q1. CTE(WITH)์— ๋Œ€ํ•œ ์„ค๋ช…์œผ๋กœ ๊ฐ€์žฅ ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์€?
A. CTE๋Š” ์‹คํ–‰ํ•˜๋ฉด DB์— ์˜๊ตฌ ํ…Œ์ด๋ธ”๋กœ ์ €์žฅ๋œ๋‹ค
B. CTE๋Š” ๋‹จ์ผ statement ๋ฒ”์œ„์—์„œ๋งŒ ์กด์žฌํ•˜๋ฉฐ, ๊ทธ statement ์•ˆ์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค
C. CTE๋Š” GROUP BY๊ฐ€ ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋˜์–ด์•ผ ํ•œ๋‹ค
D. CTE๋Š” MySQL์—์„œ ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค

Q2. MySQL์—์„œ ์•„๋ž˜์ฒ˜๋Ÿผ FROM ์ ˆ์— ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ๋„ฃ์„ ๋•Œ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ฒƒ์€?

SELECT *
FROM (SELECT course_id FROM basic.courses);


A. WHERE ์ ˆ
B. ORDER BY ์ ˆ
C. ํŒŒ์ƒ ํ…Œ์ด๋ธ”(derived table)์˜ ๋ณ„์นญ(alias)
D. LIMIT ์ ˆ

 

Q3. `EXISTS` ์„œ๋ธŒ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ์„ค๋ช…์œผ๋กœ ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์€?
A. ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ 0ํ–‰์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด EXISTS๋Š” TRUE์ด๋‹ค
B. ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ 1ํ–‰ ์ด์ƒ์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด EXISTS๋Š” TRUE์ด๋‹ค
C. EXISTS๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ์˜ SELECT ์ปฌ๋Ÿผ ๋ชฉ๋ก์„ ๋ฐ˜๋“œ์‹œ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•ด์„œ ๊ณ„์‚ฐํ•œ๋‹ค
D. EXISTS๋Š” ๋ฐ˜๋“œ์‹œ GROUP BY์™€ ํ•จ๊ป˜ ์จ์•ผ ํ•œ๋‹ค

Q4. `CASE WHEN`(CASE ํ‘œํ˜„์‹) ๋™์ž‘์— ๋Œ€ํ•œ ์„ค๋ช…์œผ๋กœ ๊ฐ€์žฅ ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์€?
A. ๋ชจ๋“  WHEN ์กฐ๊ฑด์„ ๋๊นŒ์ง€ ํ‰๊ฐ€ํ•œ ๋’ค, TRUE์ธ THEN ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋‘ ํ•ฉ์ณ ๋ฐ˜ํ™˜ํ•œ๋‹ค
B. ์œ„์—์„œ๋ถ€ํ„ฐ ์กฐ๊ฑด์„ ํ‰๊ฐ€ํ•˜๋ฉฐ **์ฒ˜์Œ TRUE๊ฐ€ ๋œ THEN์˜ ๊ฐ’**์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ELSE๊ฐ€ ์—†๊ณ  ์กฐ๊ฑด์ด ๋ชจ๋‘ FALSE๋ฉด NULL์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค
C. CASE๋Š” WHERE ์ ˆ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
D. CASE๋Š” ์ˆซ์ž ๊ฒฐ๊ณผ๋งŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค

Q5. `IFNULL(expr1, expr2)`์˜ ๋™์ž‘์œผ๋กœ ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ์€?
A. expr1์ด NULL์ด๋ฉด expr1์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค
B. IFNULL์€ ์ธ์ž๋ฅผ 3๊ฐœ ์ด์ƒ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค
C. expr1์ด NULL์ด ์•„๋‹ˆ๋ฉด expr1์„, NULL์ด๋ฉด expr2๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค
D. IFNULL์€ NULL ๊ฐ’์„ ๋‹ค๋ฅธ ๊ฐ’์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์—†๋‹ค


# ์ž๊ธฐ์ฃผ๋„ํ•™์Šต์„ ์œ„ํ•œ AIํ™œ์šฉ๋ฒ• ์„ธ์…˜ 1ํšŒ์ฐจ

๊ทธ๋ ‡๋‹ค๋ฉด ์•ž์œผ๋กœ ์ค‘์š”ํ•œ ๊ฒƒ์ด ๋ฌด์—‡์ผ๊นŒ?

1. ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•ด ๋‚ผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.


<๋‚ด์ผ์˜ ํ•™์Šต>

  • ๋ผ์ด๋ธŒ ์„ธ์…˜
    • SQL ๋ผ์ด๋ธŒ์„ธ์…˜ 6ํšŒ์ฐจ
    • ์ž๊ธฐ์ฃผ๋„ํ•™์Šต์„ ์œ„ํ•œ AIํ™œ์šฉ๋ฒ• 2ํšŒ์ฐจ
  • ๊ฐœ์ธํ•™์Šต
    • SQL ์ฝ”๋“œ์นดํƒ€ 30์ผ, 31์ผ ๋ถ„๋Ÿ‰
    • ํŒ€ ์•„ํ‹ฐํด: ๋ฐ์ดํ„ฐ ๋ถ„์„๊ฐ€๊ฐ€ ๊ฐ–์ถฐ์•ผํ•  9๊ฐ€์ง€ ์—ญ๋Ÿ‰
    • Sub_์‚ฌ์บ  SQL ๋‹ฌ๋ฆฌ๊ธฐ๋ฐ˜ ๋ฌธ์ œํ’€์ด (4๋ฒˆ~)