PostgreSQL: إنشاء وتعديل الجداول في PostgreSQL
آخر تحديث: 2026-08-26
الجدول هو أهم كائن في قاعدة البيانات — إنه "جدول البيانات" الذي يخزن بياناتك، حيث كل صف هو سجل وكل عمود هو حقل.
1. ما ستتعلمه
- CREATE TABLE لإنشاء جدول (تعريفات الأعمدة، القيود، القيم الافتراضية)
- جولة سريعة في أنواع البيانات الشائعة في PostgreSQL
- قيود PRIMARY KEY / FOREIGN KEY / UNIQUE / NOT NULL / CHECK
- ALTER TABLE لتعديل هيكل الجدول
- DROP TABLE لحذف جدول
\dفي psql لفحص هيكل الجدول
2. قصة حقيقية من فريق تجارة إلكترونية
(1) الألم: كيفية تصميم ثلاثة جداول أساسية
حصل فريق Alice على متطلب جديد: إنشاء 3 جداول أساسية لنظام التجارة الإلكترونية — users (المستخدمون)، products (المنتجات)، و orders (الطلبات). المتطلبات هي:
- جدول المستخدمين: البريد الإلكتروني فريد، كلمة المرور غير فارغة، وقت التسجيل يسجل تلقائياً
- جدول المنتجات: السعر يجب أن يكون أكبر من 0، المخزون لا يمكن أن يكون سالباً
- جدول الطلبات: مرتبط بالمستخدم والمنتج، الحالة مقصورة على مجموعة قيم ثابتة
كانت Alice غير متأكدة: أين يجب وضع القيود؟ كيف تختار أنواع البيانات؟ كيف تعد الحذف المتتالي للمفاتيح الخارجية؟
(2) الحل: CREATE TABLE + القيود
PostgreSQL تتيح لك إعلان جميع القيود مباشرة عند إنشاء الجدول، لتضمن قاعدة البيانات جودة بياناتك نيابة عنك:
-- إنشاء جدول المستخدمين مع تفرد البريد الإلكتروني وطابع زمني تلقائي
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) المكسب
- جودة البيانات مضمونة على مستوى قاعدة البيانات (مستحيل إدراج منتج بسعر < 0)
- الحذف المتتالي للمفاتيح الخارجية (حذف مستخدم يحذف تلقائياً جميع طلباته)
- القيم الافتراضية تقلل كود طبقة التطبيق (
created_atيملأ تلقائياً)
3. صيغة CREATE TABLE
(1) هيكل الصيغة الكامل
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) قيود مستوى الجدول
-- مفتاح أساسي مركب
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 ثنائي (موصى به) | استعلامات مفهرسة سريعة |
5. القيود بالتفصيل
(1) PRIMARY KEY
graph TB
PK[PRIMARY KEY] --> U[UNIQUE<br/>لا قيم مكررة]
PK --> NN[NOT NULL<br/>لا يمكن أن يكون فارغاً]
PK --> IDX[فهرس تلقائي<br/>B-Tree ينشأ تلقائياً]
(1) ▶ مثال
-- مفتاح أساسي أحادي العمود (الأكثر شيوعاً)
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:
CREATE TABLE
(2) FOREIGN KEY
| إجراء التتالي | سلوك ON DELETE | سلوك ON UPDATE |
|---|---|---|
CASCADE |
حذف متتالي (حذف مستخدم → حذف طلباته) | تحديث متتالي |
SET NULL |
تعيين إلى NULL | تعيين إلى NULL |
SET DEFAULT |
تعيين إلى القيمة الافتراضية | تعيين إلى القيمة الافتراضية |
RESTRICT |
رفض الحذف (السلوك الافتراضي) | رفض التحديث |
NO ACTION |
نفس RESTRICT (معيار SQL) | نفس RESTRICT |
(2) ▶ مثال
-- عناصر الطلب: حذف الطلب -> حذف جميع عناصره (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:
CREATE TABLE
(3) قيد CHECK
(3) ▶ مثال
-- السعر يجب أن يكون موجباً، الخصم لا يمكن أن يتجاوز السعر
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:
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) ▶ مثال
-- إضافة عمود جديد
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:
-- SQL statement executed successfully
ALTER TABLE ... ALTER COLUMN ... TYPE ... USING ... وتأكد من أ�� عبارة USING تحول بشكل صحيح.
7. DROP TABLE
(5) ▶ مثال
-- حذف آمن (لا خطأ إذا لم يكن الجدول موجوداً)
DROP TABLE IF EXISTS test_table;
-- حذف متتالي (يحذف أيضاً الكائنات التابعة مثل طرق العرض)
DROP TABLE IF EXISTS users CASCADE;
Output:
-- SQL statement executed successfully
| الخيار | الوصف |
|---|---|
IF EXISTS |
لا خطأ إذا لم يكن الجدول موجوداً |
CASCADE |
يحذف أيضاً الكائنات المعتمدة على هذا الجدول (طرق العرض، مراجع المفاتيح الخارجية، إلخ) |
RESTRICT |
يرفض الحذف عندما تكون هناك كائنات تابعة (السلوك الافتراضي) |
pg_dump نسخة احتياطية أولاً في الإنتاج.
8. فحص هيكل الجدول بـ psql
| الأمر | الوظيفة | مثال |
|---|---|---|
\dt |
سرد جميع الجداول | \dt |
\dt+ |
سرد الجداول (مع معلومات الحجم) | \dt+ |
\d tablename |
عرض هيكل الجدول | \d users |
\d+ tablename |
عرض هيكل الجدول (مفصل) | \d+ users |
(6) ▶ مثال
# سرد جميع الجداول في قاعدة البيانات الحالية
\dt
# عرض هيكل جدول users
\d users
Output:
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. مثال كامل: الجداول الأساسية الثلاثة للتجارة الإلكترونية
-- ============================================
-- مثال كامل: الجداول الأساسية للتجارة الإلكترونية
-- المستخدمون، المنتجات، الطلبات مع القيود المناسبة
-- ============================================
-- 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
❓ أسئلة شائعة
CREATE INDEX CONCURRENTLY (مغطى في درس لاحق) أو نفذ خلال نافذة صيانة.📖 ملخص
- CREATE TABLE يعرف هيكل الجدول؛ تعريفات الأعمدة تشمل نوع البيانات + القيد + الافتراضي
- اختيار نوع البيانات: INTEGER/SERIAL للأعداد الصحيحة، DECIMAL للمال، TIMESTAMPTZ للوقت، JSONB للهياكل المرنة
- خمسة قيود رئيسية: PRIMARY KEY / FOREIGN KEY / UNIQUE / NOT NULL / CHECK
- تتاليات المفاتيح الخارجية: CASCADE (متتالي) / SET NULL / RESTRICT (افتراضي) — اختر حسب حاجة العمل
- ALTER TABLE يمكنه إضافة/حذف/إعادة تسمية الأعمدة وتعديل الأنواع والقيود
- DROP TABLE لا يمكن التراجع عنه؛ IF EXISTS يمنع الأخطاء؛ CASCADE يحذف الكائنات التابعة
\dفي psql يعرض هيكل الجدول،\dtيسرد جميع الجداول
📝 تمارين
-
أساسي (★): أنشئ جدول
categories(id, name, description, created_at)، حيث name يجب أن يكون NOT NULL و UNIQUE. بعد إدراج 3 صفوف اختبارية، استخدم\d categoriesلفحص هيكل الجدول. -
متوسط (★★): بناءً على الجداول الأساسية الثلاثة للتجارة الإلكترونية المنشأة في هذا الدرس، استخدم ALTER TABLE لإضافة عمود
last_login_at TIMESTAMPTZوعمودlogin_count INTEGER DEFAULT 0إلى جدولusers. ثم أضف قيد CHECK يضمن أنlogin_countلا يمكن أن يكون سالباً. -
متقدم (★★★): أنشئ جدول
product_reviewsمع: id (مفتاح أساسي)، product_id (مفتاح خارجي يشير إلى products)، user_id (مفتاح خارجي يشير إلى users)، rating (1–5، قيد CHECK)، title، content، created_at. المتطلبات: عند حذف مستخدم، احتفظ بالمراجعة لكن عيّن user_id إلى NULL؛ عند حذف منتج، احذف متتالياً جميع مراجعاته.