Skip to content

Commit 14b025a

Browse files
committed
Update SQL Post " [Programmers] SQL > JOIN 풀이 모음 "
- 이전에 풀었던 문제 복습 및 내용 보완
1 parent f09d49f commit 14b025a

File tree

1 file changed

+129
-32
lines changed

1 file changed

+129
-32
lines changed

_posts/2023-12-27-SQL-Join.md

Lines changed: 129 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ ORDER BY SALES DESC, PRODUCT_CODE ASC
108108
```
109109

110110

111+
---
112+
111113
## 조건에 맞는 도서와 저자 리스트 출력하기(Lv.2)
112114

113115
> [조건에 맞는 도서와 저자 리스트 출력하기](https://school.programmers.co.kr/learn/courses/30/lessons/144854)
@@ -216,7 +218,10 @@ ORDER
216218

217219
* 1번째 보다 더 효율적이라고 생각한다.
218220

219-
## 오랜 기간 보호한 동물(1)
221+
222+
---
223+
224+
## 오랜 기간 보호한 동물(1) (Lv.3)
220225

221226
> [오랜 기간 보호한 동물(1)](https://school.programmers.co.kr/learn/courses/30/lessons/59044)
222227
@@ -226,15 +231,15 @@ ORDER
226231

227232
이때 결과는 보호 시작일 순으로 조회해야 합니다.
228233

229-
### Answer Code(24.01.03)
234+
### Answer Code (25.09.04)
230235

231236
```sql
232-
SELECT A.NAME, A.DATETIME
233-
FROM ANIMAL_INS A
234-
LEFT JOIN ANIMAL_OUTS B ON A.ANIMAL_ID = B.ANIMAL_ID
235-
WHERE B.DATETIME IS NULL
236-
ORDER BY A.DATETIME
237-
LIMIT 3
237+
SELECT INS.NAME, INS.DATETIME
238+
FROM ANIMAL_INS AS INS
239+
LEFT JOIN ANIMAL_OUTS AS OUTS ON INS.ANIMAL_ID = OUTS.ANIMAL_ID
240+
WHERE OUTS.DATETIME IS NULL
241+
ORDER BY INS.DATETIME
242+
LIMIT 3
238243
```
239244

240245
### 문제 풀이
@@ -247,48 +252,79 @@ ANIMAL_OUTS - 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중
247252
248253
* `ANIMAL_ID`를 기준으로 `ANIMAL_INS` 테이블과 `ANIMAL_OUTS` 테이블을 JOIN
249254

250-
* 아직 입양을 못간 동물 조회(WHERE) -> WHERE B.DATETIME IS NULL
255+
* `JOIN`: ANIMAL_INS 테이블(INS)을 기준으로, ANIMAL_OUTS 테이블(OUTS)과 ANIMAL_ID로 LEFT JOIN 한다.
256+
257+
* **입양 못 간 동물 조회 (WHERE)**: LEFT JOIN을 하면 입양 기록이 없는 동물의 OUTS 테이블 정보는 `NULL` 이 된다. 이 원리를 이용해 `WHERE OUTS.DATETIME IS NULL` 조건으로 입양 가지 못한 동물만 골라낸다.
258+
259+
* 정렬 (ORDER BY): 가장 오래 보호소에 있었던 동물'은 **'보호 시작일이 가장 빠른 동물'** 과 같다. 따라서 보호 시작일 순서대로 정렬한다. (ORDER BY INS.DATETIME)
260+
261+
* 참고로, ORDER BY의 **기본 정렬은 오름차순(ASC)** 이다.
262+
263+
* 결과 수 제한 (LIMIT): 정렬된 결과 중 상위 3마리만 선택한다. (LIMIT 3)
264+
265+
* 최종 조회 (SELECT): 해당 동물의 이름(INS.NAME)과 보호 시작일(INS.DATETIME)을 조회한다.
266+
267+
> LIMIT 3가 마지막에 오는 이유
268+
269+
* LIMIT가 마지막에 오는 이유는 **SQL 쿼리의 실행 순서** 때문이다.
270+
271+
* 보통은 쿼리의 실행 순서는 아래와 같이 진행된다.
272+
273+
* (1) FROM / JOIN: NIMAL_INS와 ANIMAL_OUTS 테이블을 합친다.
251274

252-
* 3마리 이름과 보호 시작일 조회(SELECT) -> A.NAME, A.DATETIME (A: ANIMAL_INS) / LIMIT 3
275+
* (2) WHERE: 친 데이터에서 입양 간 동물들을 제외한다. (OUTS.DATETIME IS NULL).
253276

254-
* 결과는 보호 시작일 순으로 조회, 가장 오래 보호소에 있었던 동물 -> ORDER BY A.DATETIME (기본이 내림차순)
277+
* (3) ORDER BY: 은 동물들을 보호 시작일(INS.DATETIME) 순서대로 정렬한다.
255278

256-
## 없어진 기록 찾기(1)
279+
* (4) SELECT: 정렬된 결과에서 이름과 보호 시작일을 선택한다.
280+
281+
* (5) LIMIT: 최종적으로 정렬된 결과의 맨 위에서 3개만 잘라낸다.
282+
283+
* 따라서 **원하는 순서대로 모든 데이터를 정렬한 뒤**(`ORDER BY`), 그중에서 원하는 개수만큼만 가져오기 위해 `LIMIT`**항상 `ORDER BY `뒤에 위치**해야 한다.
284+
285+
---
286+
287+
## 없어진 기록 찾기 (LV.3)
257288

258289
> [없어진 기록 찾기](https://school.programmers.co.kr/learn/courses/30/lessons/59042)
259290
260-
* 문제: 천재지변으로 인해 일부 데이터가 유실되었습니다.
291+
* 문제:
292+
293+
* 천재지변으로 인해 일부 데이터가 유실되었습니다.
261294

262-
입양을 간 기록은 있는데,
295+
* 입양을 간 기록은 있는데,
263296

264-
보호소에 들어온 기록이 없는 동물의 ID와 이름을 ID 순으로 조회하는 SQL문을 작성해주세요.
297+
* 보호소에 들어온 기록이 없는 동물의 ID와 이름을 ID 순으로 조회하는 SQL문을 작성해주세요.
265298

266-
### Answer Code(24.01.03)
299+
### Answer Code 1(24.01.03)
267300

268301
```sql
269-
SELECT B.ANIMAL_ID, B.NAME
270-
FROM ANIMAL_INS A
271-
RIGHT JOIN ANIMAL_OUTS AS B ON A.ANIMAL_ID = B.ANIMAL_ID
272-
WHERE A.ANIMAL_ID IS NULL
273-
ORDER BY B.ANIMAL_ID
302+
SELECT O.ANIMAL_ID, O.NAME
303+
FROM ANIMAL_INS AS I
304+
RIGHT JOIN ANIMAL_OUTS AS O ON I.ANIMAL_ID = O.ANIMAL_ID
305+
WHERE I.ANIMAL_ID IS NULL
306+
ORDER BY O.ANIMAL_ID;
274307
```
275308

276-
### 문제 풀이
309+
### Answer Code 1 - 문제 풀이
277310

278-
ANIMAL_INS - 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부
311+
ANIMAL_INS
312+
- 동물 보호소에 들어온 동물의 정보.
313+
- 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부
279314

280-
ANIMAL_OUTS - 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부
315+
ANIMAL_OUTS
316+
- 동물 보호소에서 입양 보낸 동물의 정보
317+
- 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부
281318

282319
> 문제를 풀기 위해서 해야할 작업들
283320
284-
* `ANIMAL_OUTS` 테이블 기준으로 `ANIMAL_INS` 테이블과 ANIMAL_ID으로 **RIGHT JOIN**
321+
* `ANIMAL_OUTS` 테이블 기준으로 `ANIMAL_INS` 테이블과 `ANIMAL_ID`으로 **RIGHT JOIN**
285322

286323
* 입양일은 존재하나, 보호 시작일이 존재하지 않은 동물 -> ANIMAL_INS 테이블에서 ANIMAL_ID가 없는 경우
287324

288325
* ID와 이름을 조회(SELECT)
289326

290327
* ID 순으로 조회(ORDER)
291-
292328
---
293329

294330
![](/assets/img/sql/sql-right-join.png)
@@ -299,10 +335,40 @@ ANIMAL_OUTS - 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별
299335

300336
* 예를 들어, TABLE_A LEFT JOIN TABLE_B -> TABLE_A의 결과는 모두 노출하고 A와 교집합이 있는 B만 추가로 추출한다는 뜻이다.
301337

302-
* 이 문제에서는 `ANIMAL_OUTS` 테이블을 기준으로 ID와 이름을 조회할 때 **RIGHT JOIN**을 사용하면, 오른쪽에는 `ANIMAL_OUTS` 테이블을 작성하고,
303-
왼쪽인 FROM 절 뒤에는 `ANIMAL_OUTS` 테이블이 아닌 `ANIMAL_INS` 테이블을 작성한다.
338+
* 이 문제에서는 `ANIMAL_OUTS` 테이블을 기준으로 ID와 이름을 조회할 때 **RIGHT JOIN**을 사용하면,
339+
* 오른쪽에는 `ANIMAL_OUTS` 테이블을 작성하고, 왼쪽인 FROM 절 뒤에는 `ANIMAL_OUTS` 테이블이 아닌 `ANIMAL_INS` 테이블을 작성한다.
304340

305-
## 있었는데요 없었습니다.
341+
342+
### Answer Code 2(25.09.04)
343+
344+
```sql
345+
-- ANIMAL_INS: 동물 보호소에 들어온 동물의 정보
346+
-- ANIMAL_OUTS: 동물 보호소에서 입양 보낸 동물의 정보
347+
-- 보호소에 들어온 기록이 없는 동물의 ID, 이름을 ID순으로 조회
348+
-- Allie -> 입양 보낸 기록은 있는데, 들어온 기록은 없음
349+
-- Spice -> 역시 마찬가지
350+
351+
SELECT O.ANIMAL_ID, O.NAME
352+
FROM ANIMAL_OUTS AS O
353+
LEFT JOIN ANIMAL_INS AS I ON O.ANIMAL_ID = I.ANIMAL_ID
354+
WHERE I.ANIMAL_ID IS NULL
355+
ORDER BY O.ANIMAL_ID;
356+
```
357+
358+
### Answer Code 2 - 문제 풀이
359+
360+
* `ANIMAL_OUTS` 테이블을 기준으로 `ANIMAL_INS` 테이블과 `ANIMAL_ID`로 LEFT JOIN을 수행한다.
361+
362+
* 입양 기록(`ANIMAL_OUTS`)은 있지만 보호소에 들어온 기록(`ANIMAL_INS`)이 없는 동물을 찾는다. (`WHERE I.ANIMAL_ID IS NULL` 조건)
363+
364+
* 찾아낸 동물의 ID와 이름을 조회(`SELECT`)한다.
365+
366+
* 결과를 ID 순으로 정렬(`ORDER BY`)한다.
367+
368+
369+
---
370+
371+
## 있었는데요 없었습니다. (LV.3)
306372

307373
> [있었는데요 없었습니다](https://school.programmers.co.kr/learn/courses/30/lessons/59043)
308374
@@ -312,7 +378,7 @@ ANIMAL_OUTS - 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별
312378

313379
이때 결과는 보호 시작일이 빠른 순으로 조회해야합니다.
314380

315-
### Answer Code(24.01.04)
381+
### Answer Code 1(24.01.04)
316382

317383
```sql
318384
SELECT ANIMAL_ID, NAME
@@ -322,7 +388,7 @@ WHERE B.DATETIME < A.DATETIME
322388
ORDER BY B.DATETIME
323389
```
324390

325-
### 문제 풀이
391+
### Answer Code 1 - 문제 풀이
326392

327393
ANIMAL_INS - 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부
328394

@@ -340,6 +406,37 @@ ANIMAL_OUTS - 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별
340406

341407
* 보호 시작일을 기준으로 내림차순 정렬하여 결과를 출력한다.
342408

409+
### Answer Code 2(25.09.04)
410+
411+
```sql
412+
-- INS: 동물 보호소에 들어온 동물의 정보
413+
-- OUTS: 테이블은 동물 보호소에서 입양 보낸 동물의 정보
414+
415+
SELECT OUTS.ANIMAL_ID, OUTS.NAME
416+
FROM ANIMAL_OUTS AS OUTS
417+
LEFT JOIN ANIMAL_INS AS INS ON OUTS.ANIMAL_ID = INS.ANIMAL_ID
418+
WHERE OUTS.DATETIME < INS.DATETIME
419+
ORDER BY INS.DATETIME;
420+
```
421+
422+
### Answer Code 2 - 문제 풀이
423+
424+
* 보호 시작일(INS)보다 입양일(OUTS)이 더 빠른 동물의 아이디와 이름을 조회하는 문제.
425+
426+
* 더 빠르다는 것은 더 작다는것이므로 => `OUTS.DATETIME (입양일) < INS.DATETIME(보호 시작일)`
427+
428+
* 결과는 보호 시작일(INS)이 빠른 순 -> 오름차순
429+
430+
* 날짜와 시간 데이터에서 **'빠르다'는 것은 '더 이전'을 의미하고, 이는 곧 '더 작은 숫자'** 에 해당한다.
431+
432+
* 빠른 날짜 (과거): 2023년 1월 1일
433+
434+
* 늦은 날짜 (미래): 2025년 9월 4일
435+
436+
* 데이터로 변환하면 과거의 날짜가 더 작은 값을 가집니다. 즉, `2023-01-01` < `2025-09-04` 이다.
437+
438+
---
439+
343440
## 주문량이 많은 아이스크림들 조회하기
344441

345442
> [주문량이 많은 아이스크림들 조회하기](https://school.programmers.co.kr/learn/courses/30/lessons/133027)
@@ -410,4 +507,4 @@ ORDER BY SUM(A.TOTAL_ORDER) + SUM(B.TOTAL_ORDER) DESC LIMIT 3
410507
## Reference
411508

412509
- https://kkw-da.tistory.com/
413-
- https://habiis.tistory.com/118 (JOIN 종류)
510+
- https://habiis.tistory.com/118 (JOIN 종류)

0 commit comments

Comments
 (0)