خانه/ طراحی پایگاه‌داده/ ارتباطات

ارتباطات: یک‌به‌یک، یک‌به‌چند و چندبه‌چند

مبتدی ۱۴ دقیقه مطالعه

در طول این دوره، بارها با یک نوع رابطه (یک‌به‌چند، از طریق کلید خارجی) کار کردیم. حالا وقتش رسیده هر سه نوع رابطه‌ای که در طراحی پایگاه‌داده وجود دارد را کنار هم ببینیم، و یاد بگیریم چطور تشخیص دهیم کدام رابطه، کدام‌یک است.

یک‌به‌چند (One-to-Many) — رایج‌ترین حالت

یک ردیف از جدول اول، می‌تواند به چند ردیف از جدول دوم مرتبط باشد؛ اما هر ردیف جدول دوم، فقط به یک ردیف از جدول اول مرتبط است. مثال آشنا: هر استاد (courses.teacher) می‌تواند چند درس تدریس کند، اما هر درس فقط یک استاد دارد.

پیاده‌سازی: یک ستون FOREIGN KEY در سمت «چند» قرار می‌گیرد. دقیقاً همان الگویی که در فصل ۴ با enrollments.student_id دیدیم.

چندبه‌چند (Many-to-Many) — نیازمند جدول واسط

هر ردیف جدول اول می‌تواند به چند ردیف جدول دوم مرتبط باشد، و برعکس هم. مثال آشنا: هر دانش‌آموز می‌تواند چند درس بردارد، و هر درس می‌تواند چند دانش‌آموز داشته باشد.

چرا نمی‌شود مستقیم پیاده‌سازی کرد: اگر بخواهی یک کلید خارجی مستقیم بین students و courses بگذاری، باید یا در جدول دانش‌آموزان چند ستون درس داشته باشی (که 1NF را نقض می‌کند)، یا در جدول درس‌ها چند ستون دانش‌آموز (همان مشکل). راه‌حل همیشه یکسان است: یک جدول واسط (مثل enrollments) با دو کلید خارجی — یکی به هر طرف.

بیا این را دوباره، این‌بار با تمرکز روی خودِ جدول واسط، ببینیم:

امتحانش کن — جدول واسط enrollments
می‌بینی «علی محمدی» هم در «ریاضی» هست هم در «فیزیک» — و «ریاضی» هم هم دانش‌آموز «علی محمدی» را دارد هم «زهرا احمدی» را. دقیقاً همان چندبه‌چندی که یک کلید خارجی ساده نمی‌تواند نشانش دهد.

یک‌به‌یک (One-to-One) — کمتر رایج، اما گاهی ضروری

هر ردیف جدول اول، دقیقاً به یک ردیف جدول دوم مرتبط است، و برعکس هم همین‌طور. این نوع رابطه کمتر از دو نوع دیگر پیش می‌آید، اما یک کاربرد رایج دارد: جدا کردن اطلاعات حساس یا کم‌استفاده از جدول اصلی — مثلاً جدا نگه‌داشتن حقوق کارمندان از اطلاعات عمومی‌شان، برای کنترل دسترسی دقیق‌تر:

sql
CREATE TABLE employees (
  id INTEGER PRIMARY KEY,
  full_name TEXT NOT NULL
);

CREATE TABLE employee_salaries (
  employee_id INTEGER PRIMARY KEY REFERENCES employees(id),
  monthly_salary INTEGER
);

نکته‌ی کلیدی این‌جا: employee_salaries.employee_id هم PRIMARY KEY است هم FOREIGN KEY — یعنی همان کلید اصلی جدول والد را دوباره استفاده می‌کند، نه یک شناسه‌ی جدید و جدا. همین باعث می‌شود هر کارمند، دقیقاً یک ردیف حقوق داشته باشد، نه بیشتر. بیا امتحان کنیم:

امتحانش کن — رابطه‌ی یک‌به‌یک
چرا این کار به‌جای یک جدول واحد؟ می‌توان به employee_salaries دسترسی محدودتری داد (فقط منابع انسانی) در حالی که همه‌ی کارمندان می‌توانند به employees دسترسی داشته باشند — چیزی که در یک جدول ترکیبی واحد، پیاده‌سازی امنیتی‌اش سخت‌تر می‌شد.

راهنمای تشخیص سریع

سوالنوع رابطه
آیا هر دو طرف، حداکثر یکی از طرف دیگر دارند؟یک‌به‌یک
آیا یک طرف «چند» دارد، اما طرف مقابل فقط «یکی»؟یک‌به‌چند
آیا هر دو طرف می‌توانند چند مورد از طرف مقابل داشته باشند؟چندبه‌چند (نیازمند جدول واسط)

جمع‌بندی این درس

  • یک‌به‌چند: با یک ستون FOREIGN KEY در سمت «چند» پیاده می‌شود.
  • چندبه‌چند: همیشه به یک جدول واسط با دو کلید خارجی نیاز دارد.
  • یک‌به‌یک: با استفاده از همان کلید اصلی جدول والد، به‌عنوان کلید اصلی/خارجی جدول دوم پیاده می‌شود — مفید برای جداسازی امنیتی یا سازمانی داده.

در آخرین درس این فصل، دوباره سراغ انواع داده می‌رویم — این‌بار نه به‌عنوان یک لیست، بلکه به‌عنوان بخشی از تصمیم‌های طراحی که همین حالا یاد گرفتیم.