๐Ÿ“

8. JOIN

ย 

8.1. JOIN์ด๋ž€?

์กฐ์ธ์„ ์„ค๋ช…ํ•˜๊ธฐ ์•ž์„œ RDBMS(Relational Database Management System) ํ…Œ์ด๋ธ”์˜ ํŠน์ง•์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. RDMS์—์„œ ๋ฐ์ดํ„ฐ๋Š” ํ…Œ์ด๋ธ” ํ˜•ํƒœ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ”๋“ค์€ ๋ชฉ์ ๊ณผ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด, ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต์„ฑ์„ ์ค„์ด๊ณ  ํšจ์œจ์ ์ธ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด ๋ถ„๋ฆฌํ•˜์—ฌ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
๋ฐ์ดํ„ฐ ์ •๊ทœํ™”
  • ๋ฐ์ดํ„ฐ ์ •๊ทœํ™”๋Š” ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ  ๋ฌด๊ฒฐ์„ฑ์„ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•œ ๊ณผ์ •์ž…๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„ ์‹œ, ๋ฐ์ดํ„ฐ์˜ ์ค‘๋ณต์„ ์ตœ์†Œํ™”ํ•˜๊ณ , ๋ฐ์ดํ„ฐ์˜ ๋ฌด๊ฒฐ์„ฑ๊ณผ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค๋ฉด, ๊ณ ๊ฐ ์ •๋ณด์™€ ์ฃผ๋ฌธ ์ •๋ณด๋ฅผ ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ์ดํ„ฐ์˜ ํšจ์œจ์  ๊ด€๋ฆฌ
  • ๊ฐ ํ…Œ์ด๋ธ”์€ ๊ทธ ํ…Œ์ด๋ธ”๋งŒ์˜ ํŠน์ •ํ•œ ์ฃผ์ œ๋‚˜ ๋ชฉ์ ์— ๋งž๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ์˜ ์‚ฝ์ž…, ์ˆ˜์ •, ์‚ญ์ œ ๋“ฑ์˜ ์ž‘์—…์ด ํ…Œ์ด๋ธ” ๋ณ„๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ด๋ฃจ์–ด์ง€๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ์˜ ํšจ์œจ์ด ์ฆ๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
๋ฐ์ดํ„ฐ ๋ณด์•ˆ ๊ฐ•ํ™”
  • ํ…Œ์ด๋ธ” ๋ณ„๋กœ ์ ‘๊ทผ ๊ถŒํ•œ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด, ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณดํ˜ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ธ‰์—ฌ๋‚˜ ๊ฐœ์ธ ์ •๋ณด ๊ฐ™์€ ๋ฏผ๊ฐ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” ํ…Œ์ด๋ธ”์˜ ์ ‘๊ทผ์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๋ถ„๋ฆฌํ•˜์—ฌ ์ €์žฅํ•˜๋Š” ๊ฒƒ์€ ์ค‘๋ณต์„ฑ์„ ์ค„์ด๊ณ  ํšจ์œจ์„ฑ์„ ๋†’์ด๋Š” ๋ฐ ํฐ ๋„์›€์ด ๋˜์ง€๋งŒ, ๋•Œ๋กœ๋Š” ์ด๋Ÿฌํ•œ ๋ถ„๋ฆฌ๋œ ํ…Œ์ด๋ธ”๋“ค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•จ๊ป˜ ์กฐํšŒํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ JOIN ์—ฐ์‚ฐ์ด ์ค‘์š”ํ•˜๊ฒŒ ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค. JOIN์€ SQL์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋กœ, ๋‘ ๊ฐœ ์ด์ƒ์˜ ํ…Œ์ด๋ธ”์—์„œ ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ถ„๋ฆฌ๋œ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด, ๊ณ ๊ฐ ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ ํ…Œ์ด๋ธ”๊ณผ ์ฃผ๋ฌธ ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ ํ…Œ์ด๋ธ”์„ JOIN ํ•˜์—ฌ, ํŠน์ • ๊ณ ๊ฐ์˜ ์ฃผ๋ฌธ ๋‚ด์—ญ์„ ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

8.1.1. PK ์™€ FK

SQL์—์„œ JOIN ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•  ๋•Œ, ํ…Œ์ด๋ธ”๋“ค ์‚ฌ์ด์— ์—ฐ๊ฒฐ๊ณ ๋ฆฌ ์—ญํ• ์„ ํ•˜๋Š” ์ฃผ์š” ์š”์†Œ๋Š” "Key(ํ‚ค)"์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ‚ค๋Š” Primary Key(๊ธฐ๋ณธ ํ‚ค)์™€ Foreign Key(์™ธ๋ž˜ ํ‚ค) ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์œผ๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ํ‚ค๋“ค์„ ํ†ตํ•ด ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๊ณ , JOIN ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Primary Key(PK)
  • Primary Key๋Š” ํ…Œ์ด๋ธ” ๋‚ด์—์„œ ๊ฐ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ณ ์œ ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ค‘๋ณต๋œ ๊ฐ’์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์œผ๋ฉฐ, NULL ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ” ๋‚ด์—๋Š” ์˜ค์ง ํ•˜๋‚˜์˜ Primary Key๋งŒ ์กด์žฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Foreign Key(FK)
  • Foreign Key๋Š” ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ Primary Key๋ฅผ ์ฐธ์กฐํ•˜๋Š” ํ‚ค๋กœ, ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
  • Foreign Key๋ฅผ ํ†ตํ•ด ์ฐธ์กฐ ๋ฌด๊ฒฐ์„ฑ(Referential Integrity)์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Foreign Key๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ Primary Key ๊ฐ’๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
  • ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์€ ์—ฌ๋Ÿฌ Foreign Key๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
JOIN ์—ฐ์‚ฐ์„ ์ง„ํ–‰ํ•  ๋•Œ, FK์™€ PK ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์‹œ๋กœ, HR ๋ฐ์ดํ„ฐ ์…‹์„ ์‚ดํŽด๋ณด๋ฉด โ€œemployeesโ€ ํ…Œ์ด๋ธ”์—๋Š” ์‚ฌ์›์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€, โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์—๋Š” ๋ถ€์„œ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. โ€œemployeesโ€ ํ…Œ์ด๋ธ”์˜ FK๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์˜ PK๋ฅผ ์ฐธ์กฐํ•˜๋ฉด, ๊ฐ ์‚ฌ์›์ด ์–ด๋–ค ๋ถ€์„œ์— ์†ํ•ด ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ JOIN ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋‘ ํ…Œ์ด๋ธ”์˜ ๊ด€๋ จ ์ •๋ณด๋ฅผ ํ•จ๊ป˜ ์กฐํšŒํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
notion imagenotion image
ย 

8.1.2. JOIN์˜ ์œ ํ˜•

BigQuery๋Š” ๋‹ค์–‘ํ•œ JOIN ์œ ํ˜•์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
1. INNER JOIN
  • ์ด๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ JOIN ์œ ํ˜•์œผ๋กœ, ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์กฐ๊ฑด์— ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๋ ˆ์ฝ”๋“œ๋Š” ๊ฒฐ๊ณผ์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.
2. LEFT OUTER JOIN (๋˜๋Š” LEFT JOIN)
  • ์™ผ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ์™€ ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์—์„œ ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ํ•„๋“œ๋Š” NULL๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
3. RIGHT OUTER JOIN (๋˜๋Š” RIGHT JOIN)
  • ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ์™€ ์™ผ์ชฝ ํ…Œ์ด๋ธ”์—์„œ ์กฐ๊ฑด์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์™ผ์ชฝ ํ…Œ์ด๋ธ”์— ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ํ•ด๋‹น ํ•„๋“œ๋Š” NULL๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
4. FULL OUTER JOIN (๋˜๋Š” FULL JOIN)
  • ๋‘ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๋‘ ํ…Œ์ด๋ธ” ์ค‘ ์–ด๋Š ํ•œ์ชฝ์—๋งŒ ์กด์žฌํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋Š” ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ ํ•„๋“œ ๊ฐ’์ด NULL๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
5. CROSS JOIN
  • ๋‘ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ์กฐํ•ฉ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์ด JOIN ์œ ํ˜•์€ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„์— ์ผ์น˜ ์กฐ๊ฑด ์—†์ด ๋ชจ๋“  ์กฐํ•ฉ์˜ ๊ฒฐ๊ณผ๋ฅผ ์›ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
6. SELF JOIN
  • ํ…Œ์ด๋ธ”์„ ์ž๊ธฐ ์ž์‹ ๊ณผ JOIN ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
  • ๊ฐ™์€ ํ…Œ์ด๋ธ” ๋‚ด์—์„œ ๋ ˆ์ฝ”๋“œ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ์ฐพ์„ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ง์›๊ณผ ์ƒ์‚ฌ์ด ๋ชจ๋‘ ๊ฐ™์€ ํ…Œ์ด๋ธ”์— ์žˆ์„ ๊ฒฝ์šฐ, SELF JOIN์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์‚ฌ-์ง์› ๊ด€๊ณ„๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

8.1.3. JOIN ๋ฌธ๋ฒ•

JOIN ์—ฐ์‚ฐ์€ ANSI JOIN๊ณผ Oracle JOIN, ๋‘ ์ข…๋ฅ˜์˜ SQL ๋ฌธ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ๊ฐ JOIN ๋ฌธ๋ฒ•์˜ ์„ค๋ช… ๋ฐ ์ฃผ์š” ์ฐจ์ด์ ์„ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ANSI JOIN
American National Standards Institute (ANSI)์— ์˜ํ•ด ์ •์˜๋œ ํ‘œ์ค€ SQL JOIN์ž…๋‹ˆ๋‹ค.
  1. ํŠน์ง•: JOIN ํ‚ค์›Œ๋“œ์™€ ํ•จ๊ป˜ ์กฐ์ธ ์กฐ๊ฑด์„ ๋ช…์‹œ์ ์œผ๋กœ ON ์ ˆ์—์„œ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  1. ๊ตฌ๋ฌธ:
# INNER JOIN SELECT * FROM Table1 INNER JOIN Table2 ON Table1.column = Table2.column;
ย 
ORACLE JOIN
ORACLE JOIN์€ Oracle ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ „ํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋˜ JOIN ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
  1. ํŠน์ง•: WHERE ์ ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ์กฐ์ธ ์กฐ๊ฑด์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  1. ๊ตฌ๋ฌธ:
# INNER JOIN SELECT * FROM Table1 , Table2 WHERE Table1.column = Table2.column;
ย 
์ฃผ์š” ์ฐจ์ด์ 
  1. ๊ตฌ๋ฌธ: ANSI JOIN์€ JOIN ํ‚ค์›Œ๋“œ์™€ ON ์ ˆ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ORACLE JOIN์€ , (์ฝค๋งˆ)์™€ WHERE ์ ˆ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  1. ํ‘œ์ค€์„ฑ: ANSI JOIN์€ ANSI SQL ํ‘œ์ค€์— ๋”ฐ๋ฅธ ๊ฒƒ์ด๋ฏ€๋กœ ๋‹ค์–‘ํ•œ RDBMS์—์„œ ํ˜ธํ™˜์„ฑ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด, ORACLE JOIN์€ Oracle ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํŠนํ™”๋œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
๊ฒฐ๋ก ์ ์œผ๋กœ, ANSI JOIN์€ ํ‘œ์ค€ SQL์— ๋”ฐ๋ฅธ ์กฐ์ธ ๋ฐฉ์‹์„ ๋‚˜ํƒ€๋‚ด๋ฉฐ, ORACLE JOIN์€ Oracle ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ „ํ†ต์ ์ธ ์กฐ์ธ ๋ฐฉ์‹์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ตœ์‹  ๋ฒ„์ „์˜ Oracle ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ๋„ ANSI JOIN ๊ตฌ๋ฌธ์„ ์ง€์›ํ•˜๋ฏ€๋กœ, ํ‘œ์ค€ํ™”์™€ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ANSI ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.
ย 

8.2. JOIN ์—ฐ์‚ฐ

8.2.1. INNER JOIN

INNER JOIN์€ ๋‘ ํ…Œ์ด๋ธ” ๊ฐ„์— ์ง€์ •๋œ ์กฐ๊ฑด์— ๋งž๋Š” ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ˜ํ™˜ํ•˜๋Š” JOIN ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋‘ ํ…Œ์ด๋ธ”์—์„œ ์ง€์ •๋œ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ผ์น˜ํ•˜๋Š” ๊ฐ’์ด ์žˆ๋Š” ํ–‰๋งŒ ๊ฒฐํ•ฉํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜๋Š” ๊ฐ’์ด ์—†๋Š” ํ–‰์€ ๊ฒฐ๊ณผ์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์™ธํ•˜๊ณ , ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๋งŒ ์กฐํšŒํ•  ๋•Œ ํšจ์œจ์ ์ด๋ฉฐ, ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์˜ ํฌ๊ธฐ๋ฅผ ์ตœ์†Œํ™”ํ•˜์—ฌ ์ฒ˜๋ฆฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT * FROM Table1 [INNER] JOIN Table2 ON Table1.column = Table2.column; # ORACLE SQL JOIN SELECT * FROM Table1 , Table2 WHERE Table1.column = Table2.column;
ANSI ๋ฌธ๋ฒ•์˜ JOIN์€ ํ‘œ์ค€ SQL JOIN ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉฐ, Oracle์—์„œ ์ „ํ†ต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” JOIN ๊ตฌ๋ฌธ์€ WHERE ์ ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‘ ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.
ย 
ANSI INNER JOIN: JOIN ์กฐ๊ฑด์ด ๋ช…์‹œ์ ์œผ๋กœ INNER JOIN โ€ฆ ON ๋ถ€๋ถ„์— ํ‘œ์‹œ๋˜๋ฏ€๋กœ ์ฟผ๋ฆฌ์˜ ๊ฐ€๋…์„ฑ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด JOIN ์กฐ๊ฑด๊ณผ WHERE ์ ˆ์˜ ํ•„ํ„ฐ ์กฐ๊ฑด์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
ORACLE INNER JOIN: ์ „ํ†ต์ ์ธ Oracle JOIN ๋ฐฉ์‹์€ WHERE ์ ˆ ์•ˆ์— JOIN ์กฐ๊ฑด์„ ํฌํ•จํ•˜๋ฏ€๋กœ, JOIN ์กฐ๊ฑด๊ณผ ๋‹ค๋ฅธ ํ•„ํ„ฐ๋ง ์กฐ๊ฑด์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด HR ๋ฐ์ดํ„ฐ ์…‹๋‚ด์— ์žˆ๋Š” โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ INNER JOIN์„ ํ™œ์šฉํ•˜์—ฌ ๊ฒฐํ•ฉํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‘ ํ…Œ์ด๋ธ” ๋ชจ๋‘ โ€œdepartment_idโ€๋ผ๋Š” ๊ณตํ†ต๋œ ์ปฌ๋Ÿผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. employees ํ…Œ์ด๋ธ”์—์„œ๋Š” โ€œdepartment_idโ€ ์ปฌ๋Ÿผ์ด FK์ด๋ฉฐ, department ํ…Œ์ด๋ธ”์—์„œ๋Š” โ€œdepartment_idโ€ ์ปฌ๋Ÿผ์ด ๋‹น์—ฐํžˆ PK ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
HR ๋ฐ์ดํ„ฐ์…‹์˜ ERDHR ๋ฐ์ดํ„ฐ์…‹์˜ ERD
HR ๋ฐ์ดํ„ฐ์…‹์˜ ERD
ย 
๊ฐ ํ…Œ์ด๋ธ”์˜ โ€œdepartment_idโ€ ๊ฐ’์ด ๊ฐ™์€ ํ–‰๋ผ๋ฆฌ ํ•ฉ์ณ์ ธ์„œ ํ•˜๋‚˜์˜ ํ…Œ์ด๋ธ”์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์œผ๋กœ๋Š” ๋‘ ํ…Œ์ด๋ธ” ๋ชจ๋‘ โ€œdepartment_idโ€ ์ปฌ๋Ÿผ์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— SELECT์—์„œ ์–ด๋Š ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ์„ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ธ์ง€ ๋ฐ˜๋“œ์‹œ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ, ๊ฐ ํ…Œ์ด๋ธ”์— ๋ณ„์นญ์„ ํ™œ์šฉํ•˜๋ฉด ๋ณต์žกํ•œ ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ๊ฐ„๋‹จํ•œ ๋ช‡ ๊ธ€์ž๋กœ ์ค„์ผ ์ˆ˜ ์žˆ์–ด(ON ์ ˆ์—์„œ ๋ณ„์นญ ์‚ฌ์šฉ ๊ฐ€๋Šฅ), ์ „์ฒด์ ์ธ ์ฟผ๋ฆฌ์˜ ๊ธธ์ด์™€ ๋ณต์žก์„ฑ์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ถœ์ฒ˜: Weniv์ถœ์ฒ˜: Weniv
์ถœ์ฒ˜: Weniv
์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์‚ฌ์› ๋ฒˆํ˜ธ, ์‚ฌ์› ์ด๋ฆ„, ๋ถ€์„œ ๋ฒˆํ˜ธ ๊ทธ๋ฆฌ๊ณ  ๋ถ€์„œ ์ด๋ฆ„์„ ์กฐํšŒํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_id , d.department_name FROM `HR.employees` AS e JOIN `HR.departments` AS d ON e.department_id = d.department_id; # ORACLE SQL JOIN SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_id , d.department_name FROM `HR.employees` AS e , `HR.departments` AS d WHERE e.department_id = d.department_id;
notion imagenotion image
ย 
์ถ”๊ฐ€์ ์ธ ์˜ˆ์‹œ๋กœ INNER JOIN ์‹œ ์ฃผ์˜ํ•  ์ ์„ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ INNER JOINํ•˜๊ณ  ์‚ฌ์› ๋ฒˆํ˜ธ๊ฐ€ 170 ๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ๋ฅผ ์กฐํšŒํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์กฐํšŒ๋˜์ง€ ์•Š์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_id , d.department_name FROM `HR.employees` AS e JOIN `HR.departments` AS d ON e.department_id = d.department_id WHERE e.employee_id > 170; # ORACLE SQL JOIN SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_id , d.department_name FROM `HR.employees` AS e , `HR.departments` AS d WHERE e.department_id = d.department_id AND e.employee_id > 170;
์ฒซ ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋ฌธ์€ ANSI SQL ๋ฌธ๋ฒ•, ๋‘ ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋ฌธ์€ ORACLE SQL ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
notion imagenotion image
ย 
HR ๋ฐ์ดํ„ฐ ์…‹์˜ โ€œemployeesโ€ ํ…Œ์ด๋ธ”์˜ ์‚ฌ์›๋ฒˆํ˜ธ๊ฐ€ 178์ธ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด โ€œdepartment_idโ€ ๊ฐ€ NULL ์ž…๋‹ˆ๋‹ค. JOIN ์กฐ๊ฑด์ธ JOIN ... ON e.department_id = d.department_id ์„ ๋งŒ์กฑํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์œ„ INNER JOIN์˜ ๊ฒฐ๊ณผ์—์„œ ์‚ฌ์› ๋ฒˆํ˜ธ๊ฐ€ 178๋ฒˆ์ธ ํ–‰์€ ํฌํ•จ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
SELECT employee_id , CONCAT(first_name, last_name) AS name , department_id FROM `HR.employees` WHERE employee_id = 178;
employees ํ…Œ์ด๋ธ”์˜ ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ ๋ ˆ์ฝ”๋“œemployees ํ…Œ์ด๋ธ”์˜ ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ ๋ ˆ์ฝ”๋“œ
employees ํ…Œ์ด๋ธ”์˜ ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ ๋ ˆ์ฝ”๋“œ
ย 
์ด์ œ ์‚ฌ์›์˜ ๋ถ€์„œ์™€ ํ•ด๋‹น ๋ถ€์„œ์˜ ์ฃผ์†Œ ์ •๋ณด๋ฅผ INNER JOIN์„ ํ†ตํ•ด ์•Œ์•„๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค. ์šฐ์„ , โ€œemployeesโ€ ํ…Œ์ด๋ธ”์—์„œ "departments_id"๋ฅผ ์‚ฌ์šฉํ•ด โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•˜์—ฌ ๋ถ€์„œ๋ช…์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒ์„ธ ์ฃผ์†Œ์™€ ๋„์‹œ ์ •๋ณด๋Š” โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์˜ "location_id"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐํ•ฉํ•œ โ€œlocationsโ€ ํ…Œ์ด๋ธ”์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ, โ€œlocationsโ€ ํ…Œ์ด๋ธ” ๋‚ด์˜ "country_id"๋ฅผ ํ†ตํ•ด โ€œcountriesโ€ ํ…Œ์ด๋ธ”๊ณผ ๊ฒฐํ•ฉํ•˜์—ฌ ๊ตญ๊ฐ€ ์ •๋ณด๊นŒ์ง€ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_name , l.street_address , l.city , l.state_province , c.country_name FROM `HR.employees` AS e JOIN `HR.departments` AS d ON e.department_id = d.department_id JOIN `HR.locations` AS l ON d.location_id = l.location_id JOIN `HR.countries` AS c ON l.country_id = c.country_id; # ORACLE SQL JOIN SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_name , l.street_address , l.city , l.state_province , c.country_name FROM `HR.employees` AS e , `HR.departments` AS d , `HR.locations` AS l , `HR.countries` AS c WHERE e.department_id = d.department_id AND d.location_id = l.location_id AND l.country_id = c.country_id ORDER BY 1;
์ฒซ ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋ฌธ์€ ANSI SQL ๋ฌธ๋ฒ•, ๋‘ ๋ฒˆ์งธ ์ฟผ๋ฆฌ๋ฌธ์€ ORACLE SQL ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.
notion imagenotion image
ย 

8.2.2. LEFT JOIN

LEFT JOIN, ๋˜๋Š” LEFT OUTER JOIN์€ ์™ผ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ์™€ ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์—์„œ ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜๋Š” ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ๊ฒฐ๊ณผ์—๋Š” NULL ๊ฐ’์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
LEFT JOIN์€ ์ฃผ๋กœ ์™ผ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ ๊ฒฐ๊ณผ๋ฅผ ์›ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ชจ๋“  ์ œํ’ˆ๊ณผ ํ•ด๋‹น ์ œํ’ˆ์— ๋Œ€ํ•œ ์ฃผ๋ฌธ(์žˆ๋Š” ๊ฒฝ์šฐ)์„ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์„ ๋•Œ LEFT JOIN์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
์ถœ์ฒ˜: Weniv์ถœ์ฒ˜: Weniv
์ถœ์ฒ˜: Weniv
LEFT JOIN ๋ฌธ๋ฒ•์€ LEFT JOIN ๋˜๋Š” LEFT OUTER JOIN ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ด๋ธ” ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT * FROM Table1 LEFT [OUTER] JOIN Table2 ON Table1.column = Table2.column;
ย 
HR ๋ฐ์ดํ„ฐ ์…‹์˜ ํ…Œ์ด๋ธ”๋“ค์„ LEFT JOIN์„ ํ™œ์šฉํ•˜์—ฌ ๊ฒฐํ•ฉํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์˜ˆ์‹œ๋Š” โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์‚ฌ์› ๋ฒˆํ˜ธ, ์‚ฌ์› ์ด๋ฆ„, ๋ถ€์„œ ๋ฒˆํ˜ธ ๊ทธ๋ฆฌ๊ณ  ๋ถ€์„œ ์ด๋ฆ„์„ ์กฐํšŒํ•œ ๊ฒฐ๊ณผ์ž…๋‹ˆ๋‹ค.
SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_id , d.department_name FROM `HR.employees` AS e LEFT JOIN `HR.departments` AS d ON e.department_id = d.department_id;
notion imagenotion image
ย 
8.2.1. ์ ˆ์—์„œ INNER JOIN์œผ๋กœ ๋‘ ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ–ˆ์„ ๋•Œ, ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์กฐํšŒ๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ โ€œemployeesโ€ ํ…Œ์ด๋ธ”์—์„œ ์‚ฌ์›๋ฒˆํ˜ธ 178๋ฒˆ์˜ ๋ ˆ์ฝ”๋“œ๋Š” โ€œdepartment_idโ€๊ฐ€ NULL ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ โ€œdepartment_idโ€๋กœ ์—ฐ๊ฒฐ ์‹œ ์กฐ์ธ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜์ง€ ์•Š์•„ ๊ฒฐ๊ณผ์— ํฌํ•จ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
SELECT employee_id , CONCAT(first_name, last_name) AS name , department_id FROM `HR.employees` WHERE employee_id = 178;
employees ํ…Œ์ด๋ธ”์˜ ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ ๋ ˆ์ฝ”๋“œemployees ํ…Œ์ด๋ธ”์˜ ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ ๋ ˆ์ฝ”๋“œ
employees ํ…Œ์ด๋ธ”์˜ ์‚ฌ์› ๋ฒˆํ˜ธ 178๋ฒˆ ๋ ˆ์ฝ”๋“œ
ย 
ํ•˜์ง€๋งŒ LEFT JOIN์„ ์‚ฌ์šฉํ•˜๋ฉด ์™ผ์ชฝ ํ…Œ์ด๋ธ”์˜ ํŠน์ • ๋ ˆ์ฝ”๋“œ์— ๋Œ€ํ•ด ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์—์„œ ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†์„ ๋•Œ, ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๋Š” ๊ฒฐ๊ณผ ์—ฌ์ „ํžˆ ํฌํ•จ๋˜๋ฉฐ LEFT JOIN ๋œ ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ์ปฌ๋Ÿผ ๊ฐ’์€ NULL๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ LEFT JOIN์€ ๋ˆ„๋ฝ๋œ ๋ฐ์ดํ„ฐ๋‚˜ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ์ฐพ๋Š” ๋ฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์—์„œ NULL ๊ฐ’์„ ํ™•์ธํ•˜์—ฌ ์–ด๋–ค ๋ ˆ์ฝ”๋“œ๊ฐ€ ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์— ์—†๋Š”์ง€ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
SELECT e.employee_id , CONCAT(e.first_name, e.last_name) AS name , d.department_id , d.department_name FROM `HR.employees` AS e LEFT JOIN `HR.departments` AS d ON e.department_id = d.department_id WHERE e.employee_id > 170;
notion imagenotion image
ย 

8.2.3. RIGHT JOIN

RIGHT JOIN, ๋˜๋Š” RIGHT OUTER JOIN์€ ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ์™€ ์™ผ์ชฝ ํ…Œ์ด๋ธ”์—์„œ ์ผ์น˜ํ•˜๋Š” ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜๋Š” ์™ผ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ๊ฒฐ๊ณผ์—๋Š” NULL ๊ฐ’์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
LEFT JOIN ๊ณผ๋Š” ๋ฐ˜๋Œ€๋กœ RIGHT JOIN์€ ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ ๊ฒฐ๊ณผ๋ฅผ ์›ํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
ย 
์ถœ์ฒ˜: Weniv์ถœ์ฒ˜: Weniv
์ถœ์ฒ˜: Weniv
# ANSI SQL JOIN SELECT * FROM Table1 RIGHT [OUTER] JOIN Table2 ON Table1.column = Table2.column;
RIGHT JOIN์„ ํ™œ์šฉํ•˜๋ฉด ์˜ค๋ฅธ์ชฝ ํ…Œ์ด๋ธ”์˜ ํŠน์ • ๋ ˆ์ฝ”๋“œ๊ฐ€ ์™ผ์ชฝ ํ…Œ์ด๋ธ”์—์„œ ์ผ์น˜ํ•˜๋Š” ํ•ญ๋ชฉ์„ ๊ฐ–์ง€ ์•Š์„ ๊ฒฝ์šฐ์—๋„ ๊ทธ ๋ ˆ์ฝ”๋“œ๋Š” ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋•Œ RIGHT JOIN ๋œ ์™ผ์ชฝ ํ…Œ์ด๋ธ”์˜ ๊ด€๋ จ ์ปฌ๋Ÿผ ๊ฐ’๋“ค์€ NULL๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
ย 
HR ๋ฐ์ดํ„ฐ ์…‹์˜ โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentโ€ ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ RIGHT JOIN ์ž‘์—…์„ ์ง„ํ–‰ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜ˆ์‹œ์—์„œ๋„ โ€œemployeesโ€ ํ…Œ์ด๋ธ”์˜ FK์ธ โ€œdepartment_idโ€์™€ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์˜ PK์ธ โ€œdepartment_idโ€๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‘ ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, โ€œemployeesโ€ ํ…Œ์ด๋ธ”์€ ์™ผ์ชฝ, โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์€ ์˜ค๋ฅธ์ชฝ ์œ„์น˜์— ๋‘๊ณ  RIGHT JOIN ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
SELECT e.employee_id , e.department_id AS e_department_id , d.department_id AS d_department_id , d.department_name FROM `HR.employees` AS e RIGHT JOIN `HR.departments` AS d ON e.department_id = d.department_id ORDER BY e.department_id;
notion imagenotion image
๊ฒฐ๊ณผ ํ…Œ์ด๋ธ”์˜ โ€œd_department_idโ€ ์ปฌ๋Ÿผ์˜ 1ํ–‰๋ถ€ํ„ฐ 16ํ–‰๊นŒ์ง€์˜ ๊ฐ’๋“ค์€ ์™ผ์ชฝ์— ์œ„์น˜ํ•œ โ€œemployeesโ€ ํ…Œ์ด๋ธ”์˜ โ€œdepartment_idโ€์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฐ’์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ departments ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ํ•ญ๋ชฉ๋“ค์€ ์กฐํšŒ๋˜์ง€๋งŒ, RIGHT JOIN ๋œ โ€œemployeesโ€ ํ…Œ์ด๋ธ”์˜ โ€œemployee_idโ€์™€ โ€œe_department_idโ€๋Š” NULL ๊ฐ’์ด ๋ฐ˜ํ™˜๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

8.2.4. FULL OUTER JOIN

FULL OUTER JOIN์€ ๋‘ ํ…Œ์ด๋ธ” ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ํ–‰์„ ํฌํ•จํ•˜๋Š” ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ํ…Œ์ด๋ธ”์—์„œ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ์—ด์€ NULL ๊ฐ’์œผ๋กœ ์ฑ„์›Œ์ง‘๋‹ˆ๋‹ค.
์•ž์„œ ์„ค๋ช…ํ•œ LEFT JOIN๊ณผ RIGHT JOIN์„ ํ•ฉ์นœ ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
์ถœ์ฒ˜: Weniv์ถœ์ฒ˜: Weniv
์ถœ์ฒ˜: Weniv
# ANSI SQL JOIN SELECT * FROM Table1 FULL [OUTER] JOIN Table2 ON Table1.column = Table2.column;
ANSI SQL JOIN ๋ฌธ๋ฒ•์—์„œ FULL OUTER JOIN ์€ OUTER๋ฅผ ์ƒ๋žตํ•˜๊ณ  FULL JOIN์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
โ€œHRโ€ ๋ฐ์ดํ„ฐ์…‹์„ ์‚ฌ์šฉํ•ด์„œ ์‹ค์Šตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. โ€œemployeesโ€ ํ…Œ์ด๋ธ”๊ณผ โ€œdepartmentsโ€ ํ…Œ์ด๋ธ”์„ FULL OUTER JOIN ํ•ด์„œ ๋ชจ๋“  ๋ถ€์„œ์™€ ๋ชจ๋“  ์ง์›์„ ์กฐํšŒํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ €, โ€œemployeesโ€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
SELECT employee_id , first_name , last_name , department_id FROM `HR.employees` WHERE department_id IS NULL;
notion imagenotion image
โ€œemployeesโ€ ํ…Œ์ด๋ธ” ์ค‘ ๋ถ€์„œ ID (โ€department_idโ€) ์ •๋ณด๊ฐ€ ์—†๋Š” ๋ฐ์ดํ„ฐ 1๊ฐœ ํ–‰์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
JOIN ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์ „์— โ€œemployeesโ€ํ…Œ์ด๋ธ”์˜ ๊ณ ์œ ํ•œ โ€œdepartment_idโ€์™€ โ€œdepartmentsโ€ํ…Œ์ด๋ธ”์˜ ๊ณ ์œ ํ•œ โ€œdepartment_idโ€๋ฅผ ๋น„๊ตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. โ€œdepartmentsโ€ํ…Œ์ด๋ธ”์˜ โ€œdepartment_idโ€ ์ค‘ โ€œemployeesโ€ํ…Œ์ด๋ธ”์˜ โ€œdepartment_idโ€ ์™€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฐ’์ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
# ์™ผ์ชฝ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ” SELECT DISTINCT department_id FROM `HR.employees` ORDER BY 1; # ์˜ค๋ฅธ์ชฝ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ” SELECT DISTINCT department_id FROM `HR.departments` ORDER BY 1;
notion imagenotion image
notion imagenotion image
ย 
โ€œdepartmentsโ€ํ…Œ์ด๋ธ”์˜ PK์ธ โ€œdepartment_idโ€์™€ โ€œemployeesโ€ํ…Œ์ด๋ธ”์˜ FK์ธ โ€œdepartment_idโ€๋ฅผ ๊ธฐ์ค€์œผ๋กœ FULL OUTER JOIN ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ…Œ์ด๋ธ”์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT e.employee_id , e.first_name , e.last_name , d.department_id FROM `HR.employees` AS e FULL JOIN `HR.departments` AS d ON e.department_id = d.department_id;
notion imagenotion image
๋ฐ์ดํ„ฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด์„œ ํ™•์ธํ–ˆ๋˜ ๊ฒƒ๊ณผ ๊ฐ™์ด โ€œemployeesโ€ํ…Œ์ด๋ธ”์—์„œ โ€œdepartment_idโ€๊ฐ€ NULL์ธ ํ–‰์ด ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์— ํฌํ•จ๋˜์—ˆ๊ณ , โ€œemployeesโ€ํ…Œ์ด๋ธ”์˜ โ€œdepartment_idโ€์™€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” โ€œdepartmentsโ€ํ…Œ์ด๋ธ”์˜ โ€œdepartment_idโ€ํ–‰์€ โ€œemployee_idโ€, โ€œfirst_nameโ€, โ€œlast_nameโ€์—ด์˜ ๊ฐ’์ด NULL ๊ฐ’์œผ๋กœ ์ฑ„์›Œ์กŒ์Šต๋‹ˆ๋‹ค.
ย 
์•ž์„œ FULL OUTER JOIN ํ•œ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ”์„ LEFT JOIN ๊ณผ RIGHT JOIN์„ ํ•ฉ์นœ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ”๊ณผ ๋น„๊ตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
(SELECT e.employee_id , e.first_name , e.last_name , d.department_id FROM `HR.employees` AS e LEFT JOIN `HR.departments` AS d ON e.department_id = d.department_id) UNION DISTINCT (SELECT e.employee_id , e.first_name , e.last_name , d.department_id FROM `HR.employees` AS e RIGHT JOIN `HR.departments` AS d ON e.department_id = d.department_id);
notion imagenotion image
UNION ์—ฐ์‚ฐ์œผ๋กœ ์ธํ•ด ๋‘ ํ…Œ์ด๋ธ”์ด ๋‹ค๋ฅด๊ฒŒ ์ •๋ ฌ๋˜์–ด ์žˆ์ง€๋งŒ, ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ” ํ–‰์˜ ์ˆ˜๋ฅผ ๋ณด๋ฉด ๊ฐ™์€ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ”์„ ๋ฐ˜ํ™˜ํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ’ก
Oracle SQL JOIN ๋ฌธ๋ฒ•์€ FULL OUTER JOIN์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, MySQL DB๋Š” ANSI JOIN ๋ฌธ๋ฒ•์ธ FULL OUTER JOIN์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, LEFT JOIN๊ณผ RIGHT JOIN ๊ฒฐ๊ณผ๋ฅผ UNION DISTINCT ์—ฐ์‚ฐํ•˜์—ฌ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
ย 

8.2.5. CROSS JOIN

CROSS JOIN์€ Cartesian Product๋ผ๊ณ ๋„ ํ•˜๋ฉฐ, ๋‘ ๊ฐœ์˜ ํ…Œ์ด๋ธ”์„ ๊ฒฐํ•ฉํ•  ๋•Œ ๋ชจ๋“  ํ–‰์˜ ์กฐํ•ฉ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” JOIN ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค.
notion imagenotion image
CROSS JOIN์€ ๊ฐ ํ–‰์ด ๋‹ค๋ฅธ ๋ชจ๋“  ํ–‰๊ณผ ๊ฒฐํ•ฉ๋ฉ๋‹ˆ๋‹ค. JOIN์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‘ ํ…Œ์ด๋ธ” ํ–‰์˜ ์ˆ˜๋ฅผ ๊ฐ๊ฐ m๊ณผ n์ด๋ผ๊ณ  ํ–ˆ์„ ๋•Œ, ์ถœ๋ ฅ๋˜๋Š” ๊ฒฐ๊ณผ ํ–‰์˜ ์ˆ˜๋Š” m x n๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. CROSS JOIN์€ ๋‹ค๋ฅธ JOIN ์—ฐ์‚ฐ๊ณผ ๋‹ค๋ฅด๊ฒŒ JOIN ์กฐ๊ฑด์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT * FROM Table1 CROSS JOIN Table2; # ORACLE SQL JOIN SELECT * FROM Table1, Table2;
CROSS JOIN์€ ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์ด ํฌ๊ณ  ์ค‘๋ณต ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. WHERE์ ˆ์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•ด์„œ JOIN ์—ฐ์‚ฐ๋Ÿ‰์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
โ€œHRโ€ ๋ฐ์ดํ„ฐ์…‹์˜ โ€œlocationsโ€ํ…Œ์ด๋ธ”๊ณผ โ€œjobsโ€ํ…Œ์ด๋ธ”์„ CROSS JOIN ํ•˜์—ฌ ๋ชจ๋“  ์ง€์—ญ์˜ ๋ชจ๋“  ์ง์—…์— ๋Œ€ํ•œ ์กฐํ•ฉ์„ ์ถœ๋ ฅํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ €, โ€œlocationsโ€ํ…Œ์ด๋ธ”๊ณผ โ€œjobsโ€ํ…Œ์ด๋ธ”์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. โ€œlocationsโ€ํ…Œ์ด๋ธ”์€ 23๊ฐœ์˜ ํ–‰, โ€œjobsโ€ํ…Œ์ด๋ธ”์€ 19๊ฐœ์˜ ํ–‰์„ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
# ์™ผ์ชฝ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ” SELECT location_id , street_address , city FROM `HR.locations`; # ์˜ค๋ฅธ์ชฝ ๊ฒฐ๊ณผ ํ…Œ์ด๋ธ” SELECT job_id , job_title FROM `HR.jobs`;
notion imagenotion image
notion imagenotion image
โ€œlocationsโ€ํ…Œ์ด๋ธ”๊ณผ โ€œjobsโ€ํ…Œ์ด๋ธ”์„ CROSS JOINํ•˜๋ฉด 23 x 19 = 437๊ฐœ ํ–‰์„ ๊ฐ€์ง„ ์ง‘ํ•ฉ์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT l.city , j.job_title FROM `HR.locations` AS l CROSS JOIN `HR.jobs` AS j; # ORACLE SQL JOIN SELECT l.city , j.job_title FROM `HR.locations` AS l, `HR.jobs` AS j;
notion imagenotion image
์œ„์˜ ์˜ˆ์‹œ์™€ ๊ฐ™์ด CROSS JOIN์€ ๋‘ ํ…Œ์ด๋ธ” ์‚ฌ์ด์˜ ๋ชจ๋“  ํ–‰์˜ ์กฐํ•ฉ์„ ์ถœ๋ ฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ JOIN์— ๋น„ํ•ด ๊ฒฐ๊ณผ ์ง‘ํ•ฉ์ด ๋งค์šฐ ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ย 
๋‹ค์Œ์œผ๋กœ โ€œjobsโ€ํ…Œ์ด๋ธ”์˜ โ€œmax_salaryโ€์ปฌ๋Ÿผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ๋Œ€ ๊ธ‰์—ฌ๊ฐ€ 10,000 ์ด์ƒ์ธ ์ง์—…๊ณผ ๋ชจ๋“  ์ง€์—ญ์— ๋Œ€ํ•œ ์กฐํ•ฉ์„ ๊ตฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. โ€œmax_salaryโ€๊ฐ€ 10,000 ์ด์ƒ์ธ ์ง์—…์€ 10๊ฐœ์ธ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
SELECT COUNT(job_title) FROM `HR.jobs` WHERE max_salary >= 10000;
notion imagenotion image
ย 
์ถ”๊ฐ€๋กœ โ€œcountriesโ€ํ…Œ์ด๋ธ”์˜ ๊ตญ๊ฐ€๋ช…์„ ํ•จ๊ป˜ ์กฐํšŒํ•˜๊ณ , ๊ตญ๊ฐ€๋ช…์œผ๋กœ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌํ–ˆ์Šต๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT c.country_name , l.city , j.job_title FROM `HR.locations` AS l JOIN `HR.countries` AS c ON l.country_id = c.country_id CROSS JOIN `HR.jobs` AS j WHERE j.max_salary >= 10000 ORDER BY c.country_name DESC; # ORACLE SQL JOIN SELECT c.country_name , l.city , j.job_title FROM `HR.locations` AS l, `HR.countries` AS c, `HR.jobs` AS j WHERE l.country_id = c.country_id AND j.max_salary >= 10000 ORDER BY c.country_name DESC;
notion imagenotion image
โ€œmax_salaryโ€๊ฐ€ 10,000 ์ด์ƒ์ธ โ€œjobsโ€ํ…Œ์ด๋ธ”์€ 10๊ฐœ์˜ ํ–‰์„ ๊ฐ–๊ณ , โ€œlocationsโ€ํ…Œ์ด๋ธ”๊ณผ โ€œcountriesโ€ํ…Œ์ด๋ธ”์„ INNER JOIN ํ•œ ํ…Œ์ด๋ธ”์€ 23๊ฐœ์˜ ํ–‰์„ ๊ฐ€์ง€๋ฏ€๋กœ 10 x 23 = 230๊ฐœ์˜ ํ–‰์„ ๊ฐ€์ง„ ํ…Œ์ด๋ธ”์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด์™€ ๊ฐ™์ด WHERE์ ˆ์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜์—ฌ JOIN ์—ฐ์‚ฐ ํฌ๊ธฐ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

8.2.6. SELF JOIN

SELF JOIN์€ ๋™์ผํ•œ ํ…Œ์ด๋ธ” ์‚ฌ์ด์˜ JOIN ์—ฐ์‚ฐ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ JOIN ์—ฐ์‚ฐ๊ณผ ๋‹ฌ๋ฆฌ FROM์ ˆ์— ๋™์ผํ•œ ํ…Œ์ด๋ธ”์ด 2๋ฒˆ ์ด์ƒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ SELF JOIN์€ ํ…Œ์ด๋ธ” ๋‚ด ๋‹ค๋ฅธ ํ–‰๊ณผ์˜ ๊ด€๊ณ„๋ฅผ ์ฐพ๊ฑฐ๋‚˜ ๊ณ„์ธต ๊ตฌ์กฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. SELF JOIN์€ ๋™์ผํ•œ ํ…Œ์ด๋ธ”์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ฐธ์กฐํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ˜๋“œ์‹œ ํ…Œ์ด๋ธ” ๋ณ„์นญ(ALIAS)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT * FROM Table1 AS t1 [INNER|LEFT|RIGHT] JOIN Table2 AS t2 ON t1.column1 = t2.column2;
โ€œHRโ€ ๋ฐ์ดํ„ฐ์…‹์˜ โ€œemployeesโ€ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜์—ฌ SELF JOIN์„ ์‹ค์Šตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋จผ์ €, โ€œemployeesโ€ํ…Œ์ด๋ธ”์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
SELECT employee_id , first_name , email , department_id , manager_id FROM `HR.employees`;
notion imagenotion image
โ€œemployeesโ€ํ…Œ์ด๋ธ”์€ 107๋ช…์˜ ์ง์›์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ฐ–๋Š” ํ…Œ์ด๋ธ”์ž…๋‹ˆ๋‹ค. ์ด ํ…Œ์ด๋ธ”์€ ๊ฐ ์ง์›์„ ๊ด€๋ฆฌํ•˜๋Š” ์ƒ์‚ฌ์˜ โ€œemployee_idโ€(โ€manager_idโ€)๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. SELF JOIN์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง์› ์ •๋ณด์™€ ํ•จ๊ป˜ ๊ด€๋ฆฌ์ž๋ช…์„ ๋ฐ˜ํ™˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ ๊ด€๋ฆฌ์ž์˜ ๊ฒฝ์šฐ, โ€œmanager_idโ€์—ด์ด NULL ๊ฐ’์„ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์— LEFT JOIN์„ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
# ANSI SQL JOIN SELECT e.employee_id , e.first_name , e.email , e.department_id , m.employee_id AS manager_id , m.first_name AS manager_name FROM `HR.employees` AS e LEFT JOIN `HR.employees` AS m ON e.manager_id = m.employee_id;
notion imagenotion image
SELF JOIN์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ณต์žกํ•œ ๊ด€๊ณ„์™€ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋‹ค๋ฃฐ ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์กฐ์ง ๊ตฌ์กฐ, ์ œํ’ˆ ๋ฒ”์ฃผ, ๊ณ„์ธต์  ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ์™€ ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.