مرحباً، هنا نكون في دورة قاعدة البيانات باستخدام Postgres. وصلنا للدرس الأخير، وفي هذا الدرس سنبني النظام الذي تراه على الشاشة - نظام للتجارة الإلكترونية.
سيكون لدينا عدة جداول (Tables) باستخدام Terminal. دعنا في البداية نرى الجداول التي سننشئها:
Users - المستخدمونProducts - المنتجاتCategories - الفئاتهذه الثلاث جداول تمثل الأساسيات بالنسبة للجهة الأمامية.
بعد ذلك سيكون لدينا أيضاً:
Orders - الطلبيات التي يطلبها المستخدمReviews - التقييمات التي يمكن للمستخدم أن يضعها على المنتجالـ Join Table الأول هو Product_Categories. نحتاج لهذا الجدول لأننا نريد عمل علاقة بين Product و Category.
السبب: قد يكون المنتج الواحد في عدة فئات، والفئة الواحدة قد تحتوي على عدة منتجات. هذه علاقة Many-to-Many.
لذلك أخذنا الـ Join Table وسميناه Product_Categories الذي يجمع بين الجدولين.
كذلك أخذنا جدول Join آخر لربط الطلبيات مع المنتجات. جدول Order_Items سيساعدنا على تتبع أي منتجات موجودة في أي طلبية.
دعنا نبدأ بإنشاء جدول Users:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password
اشترك في النشرة البريدية
دروس جديدة، مقالات، وأدوات مباشرة لبريدك.
| العمود | النوع | الوصف |
|---|---|---|
id | SERIAL PRIMARY KEY | معرف فريد للمستخدم، يزيد تلقائياً |
username | VARCHAR(100) | اسم المستخدم، يجب أن يكون فريداً وغير فارغ |
email | VARCHAR(255) | البريد الإلكتروني، يجب أن يكون فريداً وغير فارغ |
password | TEXT | كلمة المرور (ملاحظة: يجب أن تكون مشفرة في التطبيقات الحقيقية) |
created_at | TIMESTAMP | وقت إنشاء الحساب، يتم تعيينه تلقائياً للوقت الحالي |
ملاحظة مهمة: قد تختار لـ username حد أقصى مختلف حسب احتياجاتك. تأكد من أن username و email فريدان (UNIQUE) وليسا فارغين (NOT NULL).
الآن سننشئ جدول Products:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
description TEXT,
price NUMERIC(10, 2) NOT NULL,
stock INT DEFAULT 0,
created_at TIMESTAMP DEFAULT NOW()
);| العمود | النوع | الوصف |
|---|---|---|
id | SERIAL PRIMARY KEY | معرف فريد للمنتج |
name | VARCHAR(100) | اسم المنتج، يجب أن يكون موجوداً |
description | TEXT | وصف المنتج (بدون حد أقصى للطول) |
price | NUMERIC(10, 2) | سعر المنتج برقمين عشريين |
stock | INT | عدد القطع المتوفرة (القيمة الافتراضية صفر) |
created_at | TIMESTAMP | وقت إنشاء المنتج |
ملاحظة: النوع NUMERIC(10, 2) يعني أن السعر يمكن أن يصل إلى 10 أرقام مع رقمين عشريين.
مثال: 5099.99 أو 49.99 أو 9999999.99.
الآن سننشئ جدول Categories:
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(50) NOT NULL
);| العمود | النوع | الوصف |
|---|---|---|
id | SERIAL PRIMARY KEY | معرف فريد للفئة |
name | VARCHAR(50) | اسم الفئة |
الآن دعنا نضيف بعض البيانات إلى جدول products:
INSERT INTO products (name, description, price, stock) VALUES
('Laptop', 'High performance laptop', 1299.99, 10),
('Mouse', 'Wireless mouse', 29.99, 50),
('Keyboard', 'Mechanical keyboard', 99.99, 30),
('Monitor', '4K display monitor', 399.99, 15),
('Headphones', 'Noise-canceling headphones', 199.99, 20);بعد تنفيذ هذا الأمر، إذا عملنا SELECT * FROM products، سنرى خمسة منتجات.
الآن دعنا نضيف فئات إلى جدول categories:
INSERT INTO categories (name) VALUES
('Electronics'),
('Books'),
('Clothing'),
('Home and Kitchen');الآن لدينا أربع فئات.
المشكلة: الآن المنتج ليس مرتبطاً بأي فئة. لا توجد علاقة بين product و category.
مثلاً، لدينا:
لكننا لا نعرف أي فئة ينتمي إليها المنتج.
الحل: نحتاج لإنشاء جدول ربط (Join Table) يسمى product_categories.
بما أن العلاقة بين المنتج والفئة هي Many-to-Many (منتج واحد قد يكون في عدة فئات، وفئة واحدة قد تحتوي على عدة منتجات)، نحتاج لجدول ربط:
CREATE TABLE product_categories (
product_id INT NOT NULL,
category_id INT NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(id),
FOREIGN KEY (category_id) REFERENCES categories(id),
PRIMARY KEY (product_id, category_id)
);| العمود | النوع | الوصف |
|---|---|---|
product_id | INT | معرف المنتج، يشير إلى جدول products |
category_id | INT | معرف الفئة، يشير إلى جدول categories |
ملاحظة: نستخدم Composite Primary Key من product_id و category_id معاً لضمان عدم تكرار نفس العلاقة.
\d product_categories;سترى أن:
category_id هو مفتاح أجنبي يشير إلى المفتاح الأساسي في جدول categoriesproduct_id هو مفتاح أجنبي يشير إلى المفتاح الأساسي في جدول productsالآن دعنا نضيف علاقات بين المنتجات والفئات:
INSERT INTO product_categories (product_id, category_id) VALUES
(1, 1),
(2, 1),
(3, 1),
(4, 1),
(5, 1);لكن يمكن للمنتج أن يكون في فئات متعددة:
INSERT INTO product_categories (product_id, category_id) VALUES
(1, 2),
(3, 2);لنرى كل منتج مع فئاته، نستخدم JOIN:
SELECT p.name AS product_name, c.name AS category_name
FROM products p
INNER JOIN product_categories pc ON p.id = pc.product_id
INNER JOIN categories c ON c.id = pc.category_id;هذا الاستعلام سيجمع البيانات من ثلاث جداول ويعطينا النتيجة:
product_name | category_name
--------------|--------------
Laptop | Electronics
Mouse | Electronics
Keyboard | Electronics
Monitor | Electronics
Headphones | Electronics
Laptop | Books
Keyboard | Booksالآن سننشئ جدول Reviews للتقييمات:
CREATE TABLE reviews (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
product_id INT NOT NULL,
rating INT NOT NULL CHECK (rating BETWEEN 1 AND 5),
comment TEXT,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, product_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);| العمود | النوع | الوصف |
|---|---|---|
id | SERIAL PRIMARY KEY | معرف فريد للتقييم |
user_id | INT | معرف المستخدم الذي كتب التقييم |
product_id | INT | معرف المنتج المراد تقييمه |
rating | INT | التصنيف (من 1 إلى 5 فقط) |
comment | TEXT | التعليق (اختياري) |
created_at | TIMESTAMP | وقت كتابة التقييم |
القيود:
CHECK (rating BETWEEN 1 AND 5) - يضمن أن التصنيف يكون بين 1 و 5 فقطUNIQUE(user_id, product_id) - يضمن أن كل مستخدم يمكنه كتابة تقييم واحد فقط لكل منتجINSERT INTO users (username, email, password) VALUES
('alice', 'alice@example.com', 'hashed_password_here'),
('bob', 'bob@example.com', 'hashed_password_here'),
('charlie', 'charlie@example.com', 'hashed_password_here');ملاحظة: في التطبيقات الحقيقية، يجب أن تكون كلمات المرور مشفرة (hashed)، لكننا هنا نستخدم نصوص عادية للتوضيح فقط.
الآن دعنا نضيف بعض التقييمات:
INSERT INTO reviews (user_id, product_id, rating, comment) VALUES
(1, 1, 5, 'Very comfortable to use'),
(2, 4, 4, 'Great display quality'),
(3, 2, 5, 'Perfect mouse'),
(1, 3, 4, 'Good keyboard');إذا حاولت إضافة تقييم آخر من نفس المستخدم لنفس المنتج:
INSERT INTO reviews (user_id, product_id, rating, comment) VALUES
(1, 1, 3, 'Changed my mind');ستحصل على خطأ:
ERROR: duplicate key violates unique constraint "reviews_user_id_product_id_key"هذا يعني أن المستخدم الأول (user_id = 1) لا يمكنه كتابة أكثر من تقييم واحد للمنتج الأول (product_id = 1).
الآن سننشئ جدول Orders:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
order_date TIMESTAMP DEFAULT NOW(),
status VARCHAR(50) DEFAULT 'pending',
FOREIGN KEY (user_id) REFERENCES users(id)
);| العمود | النوع | الوصف |
|---|---|---|
id | SERIAL PRIMARY KEY | معرف فريد للطلبية |
user_id | INT | معرف المستخدم الذي عمل الطلبية |
order_date | TIMESTAMP | تاريخ ووقت الطلبية |
status | VARCHAR(50) | حالة الطلبية (pending, shipped, delivered) |
ملاحظة: نستخدم جدول منفصل order_items لحفظ تفاصيل المنتجات في كل طلبية.
قد تسأل: "لماذا لا نضع معلومات المنتجات مباشرة في جدول Orders؟"
السبب: لأن طلبية واحدة قد تحتوي على منتجات متعددة، وكل منتج قد يكون له خصائص مختلفة (مثل الحجم واللون).
مثال:
لذلك نحتاج order_items لحفظ كل منتج وكميته وسعره بشكل منفصل.
سننشئ جدول order_items بالشكل التالي:
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0),
price NUMERIC(10, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);| العمود | النوع | الوصف |
|---|---|---|
id | SERIAL PRIMARY KEY | معرف فريد للعنصر |
order_id | INT | معرف الطلبية |
product_id | INT | معرف المنتج |
quantity | INT | الكمية المشتراة |
price | NUMERIC(10, 2) | السعر في وقت الشراء |
ملاحظة: حفظ السعر في order_items مهم لأن سعر المنتج قد يتغير في المستقبل. نريد الاحتفاظ بالسعر الذي دفعه العميل وقت الشراء.
أولاً، ننشئ طلبية:
INSERT INTO orders (user_id) VALUES (1);هذا ينشئ طلبية للمستخدم الأول. order_date و status سيأخذان القيم الافتراضية.
الآن نضيف المنتجات إلى الطلبية:
INSERT INTO order_items (order_id, product_id, quantity, price) VALUES
(1, 1, 1, 1299.99),
(1, 3, 2, 99.99);هذا يعني:
SELECT * FROM order_items;ستشاهد:
id | order_id | product_id | quantity | price
---|----------|------------|----------|-------
1 | 1 | 1 | 1 | 1299.99
2 | 1 | 3 | 2 | 99.99لقد أنشأنا:
users - المستخدمونproducts - المنتجاتcategories - الفئاتproduct_categories - ربط المنتجات بالفئاتreviews - التقييماتorders - الطلبياتorder_items - عناصر الطلبياتالآن بعد أن بنينا نظام التجارة الإلكترونية، ننصحك بـ:
1. الاتصال بلغة برمجية
استخدم لغة برمجية مثل:
وأنشئ اتصالاً مع قاعدة البيانات. بعدها يمكنك عمل عمليات:
INSERT - إدراج بيانات جديدةDELETE - حذف بياناتUPDATE - تحديث البيانات2. تمارين JOIN متقدمة - جرب هذه التمارين:
3. تعلم المزيد
إذا لم تشاهد الفيديوهات السابقة في السلسلة، ننصحك بمشاهدتها. غطينا:
كل ما قمنا به في هذا الدرس كنا قد تحدثنا عنه قبلاً!
لقد بنينا نظام تجارة إلكترونية كامل باستخدام PostgreSQL. النظام يتضمن:
هذا يمثل أساس أي متجر إلكتروني حقيقي. من هنا يمكنك توسيع النظام بإضافة المزيد من الميزات والجداول حسب احتياجاتك!