PostgreSQL: إنشاء وتعديل الجداول في PostgreSQL

آخر تحديث: 2026-08-26

الجدول هو أهم كائن في قاعدة البيانات — إنه "جدول البيانات" الذي يخزن بياناتك، حيث كل صف هو سجل وكل عمود هو حقل.

1. ما ستتعلمه


2. قصة حقيقية من فريق تجارة إلكترونية

(1) الألم: كيفية تصميم ثلاثة جداول أساسية

حصل فريق Alice على متطلب جديد: إنشاء 3 جداول أساسية لنظام التجارة الإلكترونية — users (المستخدمون)، products (المنتجات)، و orders (الطلبات). المتطلبات هي:

كانت Alice غير متأكدة: أين يجب وضع القيود؟ كيف تختار أنواع البيانات؟ كيف تعد الحذف المتتالي للمفاتيح الخارجية؟

(2) الحل: CREATE TABLE + القيود

PostgreSQL تتيح لك إعلان جميع القيود مباشرة عند إنشاء الجدول، لتضمن قاعدة البيانات جودة بياناتك نيابة عنك:

SQL
-- إنشاء جدول المستخدمين مع تفرد البريد الإلكتروني وطابع زمني تلقائي
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    name VARCHAR(100) NOT NULL,
    password_hash CHAR(60) NOT NULL,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- إنشاء جدول المنتجات مع فحص السعر > 0
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    price DECIMAL(10, 2) CHECK (price > 0),
    stock INTEGER DEFAULT 0 CHECK (stock >= 0),
    attributes JSONB DEFAULT '{}'::jsonb
);

-- إنشاء جدول الطلبات مع مفاتيح خارجية وفحص الحالة
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
    product_id INTEGER REFERENCES products(id),
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    status VARCHAR(20) DEFAULT 'pending'
        CHECK (status IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')),
    created_at TIMESTAMPTZ DEFAULT NOW()
);

(3) المكسب


3. صيغة CREATE TABLE

(1) هيكل الصيغة الكامل

SQL
CREATE TABLE [IF NOT EXISTS] table_name (
    column_name data_type [column_constraint ...],
    ...
    [, table_constraint ...]
);

(2) قيود مستوى العمود

القيد الصيغة الوصف
PRIMARY KEY column_name type PRIMARY KEY مفتاح أساسي (فريد + غير فارغ)
NOT NULL column_name type NOT NULL منع NULL
UNIQUE column_name type UNIQUE القيم يجب أن تكون فريدة
DEFAULT column_name type DEFAULT value قيمة افتراضية
CHECK column_name type CHECK (condition) فحص شرط
REFERENCES column_name type REFERENCES table(col) مرجع مفتاح خارجي

(3) قيود مستوى الجدول

SQL
-- مفتاح أساسي مركب
CREATE TABLE order_items (
    order_id INTEGER,
    product_id INTEGER,
    quantity INTEGER,
    PRIMARY KEY (order_id, product_id)
);

-- مفتاح خارجي مسمى مع تتالي
CREATE TABLE comments (
    id SERIAL PRIMARY KEY,
    user_id INTEGER,
    content TEXT,
    CONSTRAINT fk_user
        FOREIGN KEY (user_id)
        REFERENCES users(id)
        ON DELETE SET NULL
);

4. أنواع البيانات في لمحة

PostgreSQL تدعم أكثر من 40 نوع بيانات؛ الأكثر شيوعاً أدناه:

الفئة النوع الوصف مثال
عدد صحيح SMALLINT 2 بايت، -32768 ~ 32767 العمر، الكميات الصغيرة
INTEGER (INT) 4 بايت، -2.1 مليار ~ 2.1 مليار عدد صحيح شائع (الافتراضي الموصى به)
BIGINT 8 بايت، ±9.2 تريليون المعرفات الكبيرة، المبالغ (بالسنتات)
زيادة تلقائية SERIAL زيادة تلقائية INTEGER معرف المفتاح الأساسي (موصى به)
BIGSERIAL زيادة تلقائية BIGINT مفتاح أساسي للجداول الكبي��ة
IDENTITY زيادة تلقائية بمعيار SQL (PG 10+) موصى به للمشاريع الجديدة
نقطة عائمة REAL 4 بايت، دقة 6 أرقام الحوسبة العلمية
DOUBLE PRECISION 8 بايت، دقة 15 رقماً الحوسبة العلمية
نقطة ثابتة DECIMAL(p,s) عشري دقيق السعر، المبلغ (موصى به)
NUMERIC(p,s) نفس DECIMAL نفس ما سبق
نص VARCHAR(n) طول متغير، بحد أعلى الاسم، البريد الإلكتروني
TEXT طول متغير، بدون حد أعلى الوصف، المحتوى
CHAR(n) طول ثابت قيمة التجزئة، الرمز
منطقي BOOLEAN true / false / فارغ إشارات العلم
تاريخ DATE تاريخ تاريخ الميلاد
TIMESTAMP تاريخ+وقت (بدون منطقة زمنية) الوقت المحلي
TIMESTAMPTZ تاريخ+وقت+منطقة زمنية التطبيقات العالمية (موصى به)
INTERVAL فاصل زمني حساب المدة
UUID UUID UUID 128 بت معرف موزع
JSON JSON JSON نصي توافق جيد
JSONB JSON ثنائي (موصى به) استعلامات مفهرسة سريعة
💡 تلميح: في PostgreSQL، VARCHAR و TEXT ليس لهما فرق في الأداء (على عكس MySQL). في معظم الحالات يوصى بـ VARCHAR (بحد طول) أو TEXT (بدون حد).


5. القيود بالتفصيل

(1) PRIMARY KEY

100%
graph TB
    PK[PRIMARY KEY] --> U[UNIQUE<br/>لا قيم مكررة]
    PK --> NN[NOT NULL<br/>لا يمكن أن يكون فارغاً]
    PK --> IDX[فهرس تلقائي<br/>B-Tree ينشأ تلقائياً]

(1) ▶ مثال

SQL
-- مفتاح أساسي أحادي العمود (الأكثر شيوعاً)
CREATE TABLE categories (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL
);

-- مفتاح أساسي مركب (لجداول الوصل)
CREATE TABLE product_tags (
    product_id INTEGER REFERENCES products(id),
    tag_id INTEGER REFERENCES tags(id),
    PRIMARY KEY (product_id, tag_id)
);

Output:

TEXT 📖 للعرض فقط
CREATE TABLE

(2) FOREIGN KEY

إجراء التتالي سلوك ON DELETE سلوك ON UPDATE
CASCADE حذف متتالي (حذف مستخدم → حذف طلباته) تحديث متتالي
SET NULL تعيين إلى NULL تعيين إلى NULL
SET DEFAULT تعيين إلى القيمة الافتراضية تعيين إلى القيمة الافتراضية
RESTRICT رفض الحذف (السلوك الافتراضي) رفض التحديث
NO ACTION نفس RESTRICT (معيار SQL) نفس RESTRICT

(2) ▶ مثال

SQL
-- عناصر الطلب: حذف الطلب -> حذف جميع عناصره (CASCADE)
-- الم��تج: حذف المنتج -> تعيين product_id إلى NULL (SET NULL)
CREATE TABLE order_items (
    id SERIAL PRIMARY KEY,
    order_id INTEGER REFERENCES orders(id) ON DELETE CASCADE,
    product_id INTEGER REFERENCES products(id) ON DELETE SET NULL,
    quantity INTEGER NOT NULL DEFAULT 1
);

Output:

TEXT 📖 للعرض فقط
CREATE TABLE

(3) قيد CHECK

(3) ▶ مثال

SQL
-- السعر يجب أن يكون موجباً، الخصم لا يمكن أن يتجاوز السعر
CREATE TABLE promotions (
    id SERIAL PRIMARY KEY,
    product_id INTEGER REFERENCES products(id),
    discount_price DECIMAL(10, 2) CHECK (discount_price > 0),
    start_date DATE NOT NULL,
    end_date DATE NOT NULL,
    -- CHECK في PG يمكنها الإشارة إلى أعمدة أخرى في نفس الصف!
    CHECK (end_date > start_date)
    -- ملاحظة: CHECK لا يمكنها الإشارة إلى استعلام فرعي عبر الجداول؛ التحقق عبر الجداول يحتاج مشغل
);

Output:

TEXT 📖 للعرض فقط
CREATE TABLE

6. ALTER TABLE

(1) عمليات التعديل الشائعة

العملية الصيغة الوصف
إضافة عمود ALTER TABLE t ADD COLUMN col type إضافة عمود
حذف عمود ALTER TABLE t DROP COLUMN col إزالة عمود
إعادة تسمية عمود ALTER TABLE t RENAME COLUMN old TO new إعادة تسمية عمود
تغيير النوع ALTER TABLE t ALTER COLUMN col TYPE new_type تغيير نوع البيانات
تعيين افتراضي ALTER TABLE t ALTER COLUMN col SET DEFAULT val تعيين قيمة افتراضية
حذف افتراضي ALTER TABLE t ALTER COLUMN col DROP DEFAULT إزالة القيمة الافتراضية
تعيين NOT NULL ALTER TABLE t ALTER COLUMN col SET NOT NULL جعل غير فارغ
حذف NOT NULL ALTER TABLE t ALTER COLUMN col DROP NOT NULL السماح بـ فارغ
إضافة قيد ALTER TABLE t ADD CONSTRAINT name CHECK (...) إضافة CHECK
إعادة تسمية جدول ALTER TABLE old_name RENAME TO new_name إعادة تسمية جدول

(4) ▶ مثال

SQL
-- إضافة عمود جديد
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- إضافة مع قيمة افتراضية
ALTER TABLE users ADD COLUMN is_active BOOLEAN DEFAULT true;

-- تغيير نوع العمود (يحتاج USING للأنواع غير المتوافقة)
ALTER TABLE users ALTER COLUMN phone TYPE TEXT;

-- إعادة تسمية عمود
ALTER TABLE users RENAME COLUMN phone TO phone_number;

-- تعيين قيمة افتراضية
ALTER TABLE users ALTER COLUMN is_active SET DEFAULT true;

-- إضافة قيد CHECK
ALTER TABLE products ADD CONSTRAINT price_reasonable
    CHECK (price < 100000);

-- حذف عمود
ALTER TABLE users DROP COLUMN IF EXISTS phone_number;

-- إعادة تسمية جدول
ALTER TABLE users RENAME TO customers;

Output:

TEXT 📖 للعرض فقط
-- SQL statement executed successfully
⚠️ ملاحظة: تغيير نوع العمود قد يتطلب إعادة كتابة الجدول بالكامل (مثلاً VARCHAR(50)→VARCHAR(100) لا تتطلب، لكن INTEGER→TEXT تتطلب). في الجداول الكبيرة، استخدم ALTER TABLE ... ALTER COLUMN ... TYPE ... USING ... وتأكد من أ�� عبارة USING تحول بشكل صحيح.


7. DROP TABLE

(5) ▶ مثال

SQL
-- حذف آمن (لا خطأ إذا لم يكن الجدول موجوداً)
DROP TABLE IF EXISTS test_table;

-- حذف متتالي (يحذف أيضاً الكائنات التابعة مثل طرق العرض)
DROP TABLE IF EXISTS users CASCADE;

Output:

TEXT 📖 للعرض فقط
-- SQL statement executed successfully
الخيار الوصف
IF EXISTS لا خطأ إذا لم يكن الجدول موجوداً
CASCADE يحذف أيضاً الكائنات المعتمدة على هذا الجدول (طرق العرض، مراجع المفاتيح الخارجية، إلخ)
RESTRICT يرفض الحذف عندما تكون هناك كائنات تابعة (السلوك الافتراضي)
🔥 خطأ شائع: DROP TABLE لا يمكن التراجع عنه! جميع البيانات تُفقد بشكل دائم. دائماً pg_dump نسخة احتياطية أولاً في الإنتاج.


8. فحص هيكل الجدول بـ psql

الأمر الوظيفة مثال
\dt سرد جميع الجداول \dt
\dt+ سرد الجداول (مع معلومات الحجم) \dt+
\d tablename عرض هيكل الجدول \d users
\d+ tablename عرض هيكل الجدول (مفصل) \d+ users

(6) ▶ مثال

BASH
# سرد جميع الجداول في قاعدة البيانات الحالية
\dt

# عرض هيكل جدول users
\d users

Output:

TEXT 📖 للعرض فقط
                                        Table "public.users"
   Column    |          Type          | Collation | Nullable |              Default
-------------+------------------------+-----------+----------+-----------------------------------
 id          | integer                |           | not null | nextval('users_id_seq'::regclass)
 email       | character varying(255) |           | not null |
 name        | character varying(100) |           | not null |
 password_hash | character(60)        |           | not null |
 created_at  | timestamp with time zone |         |          | now()
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "users_email_key" UNIQUE CONSTRAINT, btree (email)

9. مثال كامل: الجداول الأساسية الثلاثة للتجارة الإلكترونية

SQL
-- ============================================
-- مثال كامل: الجداول الأساسية للتجارة الإلكترونية
-- المستخدمون، المنتجات، الطلبات مع القيود المناسبة
-- ============================================

-- 1. جدول المستخدمين
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    name VARCHAR(100) NOT NULL,
    password_hash CHAR(60) NOT NULL,
    role VARCHAR(20) DEFAULT 'customer'
        CHECK (role IN ('customer', 'admin', 'manager')),
    is_active BOOLEAN DEFAULT true,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- 2. جدول المنتجات
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(200) NOT NULL,
    description TEXT,
    price DECIMAL(10, 2) NOT NULL CHECK (price > 0),
    stock INTEGER DEFAULT 0 CHECK (stock >= 0),
    category VARCHAR(50),
    attributes JSONB DEFAULT '{}'::jsonb,
    is_available BOOLEAN DEFAULT true,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- 3. جدول الطلبات مع مفاتيح خارجية
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    status VARCHAR(20) DEFAULT 'pending'
        CHECK (status IN ('pending', 'paid', 'shipped', 'delivered', 'cancelled')),
    total_amount DECIMAL(12, 2) DEFAULT 0 CHECK (total_amount >= 0),
    shipping_address TEXT,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- 4. جدول عناصر الطلب (جدول وصل)
CREATE TABLE order_items (
    id SERIAL PRIMARY KEY,
    order_id INTEGER NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
    product_id INTEGER NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    unit_price DECIMAL(10, 2) NOT NULL CHECK (unit_price > 0),
    subtotal DECIMAL(12, 2) GENERATED ALWAYS AS (quantity * unit_price) STORED
);

-- 5. إدراج بيانات نموذجية
INSERT INTO users (email, name, password_hash) VALUES
    ('alice@example.com', 'Alice', '$2a$12$dummyhashforalice1234567890abcdefghijklmnopqr'),
    ('bob@example.com', 'Bob', '$2a$12$dummyhashforbob1234567890abcdefghijklmnopqrstuv');

INSERT INTO products (name, price, stock, category, attributes) VALUES
    ('Running Shoes', 89.99, 150, 'Footwear', '{"color": "red", "size": 42}'::jsonb),
    ('Laptop Backpack', 49.99, 300, 'Accessories', '{"color": "black", "material": "nylon"}'::jsonb);

-- 6. التحقق من هيكل الجدول
\d users
\d products
\d orders
\d order_items

❓ أسئلة شائعة

س ما الفرق بين SERIAL و IDENTITY، وأيهما يجب أن أستخدم؟
ج SERIAL هي صيغة خاصة بـ PG تنشئ داخلياً تسلسلاً وتعيّن افتراضياً. IDENTITY هي صيغة بمعيار SQL (PG 10+)، بسلوك أكثر صرامة (لا يمكنك إدراج قيمة يدوياً إلا مع OVERRIDING SYSTEM VALUE). للمشاريع الجديدة، IDENTITY موصى به.
س VARCHAR أم TEXT — أيهما أختار؟
ج في PG، VARCHAR و TEXT لهما أداء متطابق. VARCHAR(n) له حد طول، TEXT ليس له حد. اقتراح: استخدم VARCHAR عندما يكون هناك حد طول واضح (مثلاً البريد الإلكتروني VARCHAR(255))، و TEXT عندما لا يكون هناك حد (مثلاً نص المقال). لا تستخدم VARCHAR بدون طول — ذلك يساوي TEXT.
س TIMESTAMP أم TIMESTAMPTZ؟
ج دائماً يوصى باستخدام TIMESTAMPTZ (مع المنطقة الزمنية). يخزن وقت UTC ويحول تلقائياً إلى المنطقة الزمنية للعميل عند العرض. TIMESTAMP ليس له منطقة زمنية ويسبب ارتباكاً في التطبيقات عبر المناطق الزمنية.
س هل الحذف المتتالي CASCADE للمفتاح الخارجي آمن؟
ج CASCADE مريح في التطوير (حذف مستخدم → حذف طلبات → حذف عناصر الطلب، تتالي ثلاثي المستويات)، لكن كن حذراً في الإنتاج — حذف مستخدم واحد عن طريق الخطأ قد يحذف كميات كبيرة من البيانات. اقتراح: استخدم RESTRICT لجداول الأعمال الحرجة، CASCADE لجداول السجلات/المؤقتة.
س هل ALTER TABLE على جدول كبير يقفل الجدول؟
ج العمليات البسيطة (ADD COLUMN مع افتراضي، زيا��ة طول VARCHAR) لا تقفل الجدول. لكن تغيير نوع البيانات، إضافة قيد NOT NULL، إلخ، تتطلب مسحاً كاملاً للجدول وستقفل الجدول. للجداول الكبيرة، استخدم CREATE INDEX CONCURRENTLY (مغطى في درس لاحق) أو نفذ خلال نافذة صيانة.
س ما هو الحد الأقصى لعدد الأعمدة في الجدول؟
ج جدول PG يمكن أن يحتوي حتى 1600 عمود (في الممارسة غالباً أقل بسبب حد حجم الصف 8KB). لكن أكثر من 50 عموداً عادة مشكلة تصميم — فكر في تقسيم الجدول أو استخدام JSONB لتخزين الحقول المتفرقة.

📖 ملخص


📝 تمارين

  1. أساسي (★): أنشئ جدول categories (id, name, description, created_at)، حيث name يجب أن يكون NOT NULL و UNIQUE. بعد إدراج 3 صفوف اختبارية، استخدم \d categories لفحص هيكل الجدول.

  2. متوسط (★★): بناءً على الجداول الأساسية الثلاثة للتجارة الإلكترونية المنشأة في هذا الدرس، استخدم ALTER TABLE لإضافة عمود last_login_at TIMESTAMPTZ وعمود login_count INTEGER DEFAULT 0 إلى جدول users. ثم أضف قيد CHECK يضمن أن login_count لا يمكن أن يكون سالباً.

  3. متقدم (★★★): أنشئ جدول product_reviews مع: id (مفتاح أساسي)، product_id (مفتاح خارجي يشير إلى products)، user_id (مفتاح خارجي يشير إلى users)، rating (1–5، قيد CHECK)، title، content، created_at. المتطلبات: عند حذف مستخدم، احتفظ بالمراجعة لكن عيّن user_id إلى NULL؛ عند حذف منتج، احذف متتالياً جميع مراجعاته.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%