العلاقات
لمعظم التطبيقات جداول تتصل ببعضها: order ينتمي إلى user، وproduct له كثير من reviews، وproject له كثير من members. تُسمّى هذه الاتصالات مفاتيح أجنبية — عمود في جدول يشير إلى صف في جدول آخر.
إنشاء مفتاح أجنبي
لا يوجد نوع عمود «Reference» بصري — تُعرَّف المفاتيح الأجنبية في SQL (في محرر SQL) أو بطلب ذكائك الاصطناعي، الذي يطبّقها كهجرة MCP.
النمط عمود عادي إضافة إلى جملة REFERENCES:
-- Add the FK as part of CREATE TABLE
CREATE TABLE public.orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id TEXT NOT NULL REFERENCES system.users(id) ON DELETE CASCADE,
total NUMERIC(10,2) NOT NULL
);
-- ...or add one to an existing table
ALTER TABLE public.orders
ADD CONSTRAINT orders_user_id_fkey
FOREIGN KEY (user_id) REFERENCES system.users(id) ON DELETE CASCADE;
بضع قواعد عامة عند ربط مفتاح أجنبي:
- سمِّ العمود حسب ما يشير إليه —
user_idوproduct_id. - طابق نوع المفتاح الأساسي للهدف — عادة
uuid. الاستثناء: إذا أشار إلى مستخدم، استخدمtext(راجع الجداول والمخطط). - اختر سلوك
ON DELETE— ما يحدث عند حذف الصف المشار إليه (انظر أدناه).
دع ذكاءك الاصطناعي يفعل ذلك
"Add a user_id foreign key on orders that cascades on delete." — يكتب عميل الذكاء الاصطناعي ALTER TABLE ويطبّقه كهجرة لك.
سلوك ON DELETE
عندما تحذف صفاً يشير إليه آخرون، يحتاج Postgres معرفة ما يفعل بالمشيرين:
| الخيار | ما يفعله | استخدمه لـ |
|---|---|---|
| CASCADE | حذف الصفوف المشيرة أيضاً | مهام المستخدم وتعليقات المنشور ورسائل الجلسة |
| SET NULL | الإبقاء على المشيرين وتعيين FK إلى NULL | مؤلف منشور — إذا غادر المؤلف، أبقِ المنشور |
| RESTRICT | حظر الحذف بالكامل | منتجات مشار إليها في طلبات — لا تحذف منتجاً أبداً إذا كان في سجل طلب أحد |
| NO ACTION | نفسه RESTRICT في معظم الحالات | نادر الاستخدام |
الأكثر أماناً افتراضياً للبيانات التي يملكها المستخدم هو CASCADE. عندما يُحذف المستخدم، تذهب مهامه معه.
واحد لكثير
الحالة الشائعة: مستخدم واحد له مهام كثيرة، منشور واحد له تعليقات كثيرة. ضع المفتاح الأجنبي على جانب الكثير:
CREATE TABLE public.posts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
user_id TEXT NOT NULL REFERENCES system.users(id) ON DELETE CASCADE
);
CREATE TABLE public.comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
post_id UUID NOT NULL REFERENCES public.posts(id) ON DELETE CASCADE,
content TEXT NOT NULL
);
منشور واحد له تعليقات كثيرة. يعيش عمود post_id على comments.
كثير لكثير
عندما يمكن لكلا الجانبين أن يكون له كثير من الآخر — يمكن للمستخدم أن يكون في مشاريع كثيرة، وللمشروع مستخدمون كثيرون — استخدم جدول محوري (يُسمّى أيضاً جدول ربط):
CREATE TABLE public.project_members (
project_id UUID NOT NULL REFERENCES public.projects(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES system.users(id) ON DELETE CASCADE,
role TEXT NOT NULL DEFAULT 'member',
joined_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (project_id, user_id)
);
المفتاح الأساسي هو تركيبة العمودين — يمكن للمستخدم أن يكون في مشروع مرة واحدة فقط. أضف أعمدة إضافية (role و joined_at) على الجدول المحوري نفسه عندما تحتاج بيانات وصفية عن العلاقة.
الاستعلام عبر العلاقات
للحصول على بيانات من جداول مرتبطة في طلب واحد، استخدم SQL JOIN في عقدة قاعدة بيانات سير عملك:
SELECT
posts.id,
posts.title,
COUNT(comments.id) AS comment_count
FROM public.posts
LEFT JOIN public.comments ON comments.post_id = posts.id
WHERE posts.user_id = ${current_user_id}
GROUP BY posts.id
ORDER BY posts.created_at DESC;
راجع بنّاء الـ API لكيفية استخدام SQL مخصص داخل سير عمل.