PostgreSQL: أنواع البيانات في PostgreSQL: الدليل الكامل

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

اختيار نوع البيانات المناسب هو أساس تصميم قاعدة البيانات — فهو يحدد كفاءة التخزين وأداء الاستعلام ودقة البيانات.

1. ما ستتعلمه


2. قصة حقيقية لمطور

(1) المشكلة: محتار بشأن أنواع البيانات

واجه Bob سلسلة من الاختيارات الصعبة عند تصميم جداول قاعدة بيانات للتجارة الإلكترونية:

(2) الحل: اخيار دقيق للنوع

يقدم PostgreSQL مجموعة غنية من أنواع البيانات المخصصة؛ الاختيار الدقيق يوفر التخزين ويضمن الدقة:

SQL
-- اختيارات الأنواع الصحيحة لقاعدة بيانات التجارة الإلكترونية
CREATE TABLE smart_products (
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,  -- معرف مقاوم للمستقبل
    name VARCHAR(200) NOT NULL,                          -- سلسلة محدودة
    description TEXT,                                    -- نص غير محدود
    price DECIMAL(10, 2) NOT NULL,                       -- مال دقيق
    weight_kg REAL,                                      -- تقريبي مقبول
    is_available BOOLEAN DEFAULT true,                   -- علم نعم/لا
    created_at TIMESTAMPTZ DEFAULT NOW(),                -- واع بالمنطقة الزمنية
    source_ip INET,                                      -- نوع عنوان IP
    attributes JSONB DEFAULT '{}'::jsonb                 -- هيكل مرن
);

(3) النتيجة


3. تدفق قرار نوع البيانات

100%
graph TB
    START[ما نوع البيانات؟] --> NUM{رقمي؟}
    NUM -->|نعم| INT{تحتاج دقة<br/>دقيقة؟}
    INT -->|نعم، مال/نسب| DEC[DECIMAL / NUMERIC]
    INT -->|لا، قياسات| FLOAT[REAL / DOUBLE PRECISION]
    NUM -->|أعداد صحيحة| RANGE{نطاق القيمة؟}
    RANGE -->|-32768 إلى 32767| SMALL[SMALLINT]
    RANGE -->|-2.1 مليار إلى 2.1 مليار| INT2[INTEGER]
    RANGE -->|أكبر| BIG[BIGINT]
    NUM -->|معرف تلقائي| AUTO[SERIAL / IDENTITY]
    START --> STR{نص؟}
    STR -->|طول ثابت| CHAR[CHAR]
    STR -->|متغير محدود| VAR[VARCHAR n]
    STR -->|غير محدود| TEXT2[TEXT]
    START --> TIME{تاريخ/وقت؟}
    TIME -->|تاريخ فقط| DATE2[DATE]
    TIME -->|وقت فقط| TIME2[TIME]
    TIME -->|طابع زمني| TZ{منطقة زمنية؟}
    TZ -->|نعم، تطبيق عالمي| TSTZ[TIMESTAMPTZ]
    TZ -->|لا، محلي فقط| TS[TIMESTAMP]
    TIME -->|مدة| IV[INTERVAL]
    START --> SPEC{خاص؟}
    SPEC -->|نعم/لا| BOOL[BOOLEAN]
    SPEC -->|UUID| UUID2[UUID]
    SPEC -->|عنوان IP| IP[INET / CIDR]
    SPEC -->|قائمة تعداد| ENUM2[ENUM]
    SPEC -->|مستند JSON| JSON[JSONB]

4. أنواع الأعداد الصحيحة

النوع التخزين النطاق الاستخدام النموذجي
SMALLINT 2 بايت -32,768 ~ 32,767 العمر، التقييم، رمز الحالة
INTEGER (INT) 4 بايت -2,147,483,648 ~ 2,147,483,647 أعداد صحيحة عامة، معرفات المفاتيح الأساسية
BIGINT 8 بايت ±9,223,372,036,854,775,807 معرفات الجداول الكبيرة، المبالغ (بالسنت)

(1) ▶ مثال

SQL
-- SMALLINT للقيم ذات النطاق الصغير
CREATE TABLE ratings (
    user_id INTEGER REFERENCES users(id),
    product_id INTEGER REFERENCES products(id),
    score SMALLINT CHECK (score BETWEEN 1 AND 5),  -- 1-5 ضمن نطاق SMALLINT تمامًا
    PRIMARY KEY (user_id, product_id)
);

-- INTEGER لمعظم المع��فات
CREATE TABLE categories (
    id SERIAL PRIMARY KEY,  -- SERIAL = INTEGER + تسلسل تلقائي
    name VARCHAR(100) NOT NULL
);

-- BIGINT للجداول عالية النمو
CREATE TABLE audit_log (
    id BIGSERIAL PRIMARY KEY,  -- BIGSERIAL = BIGINT + تلقائي
    action VARCHAR(50),
    details JSONB,
    created_at TIMESTAMPTZ DEFAULT NOW()
);

Output:

TEXT 📖 للعرض فقط
CREATE TABLE
💡 نصيحة: غير متأكد من استخدام INTEGER أم BIGINT؟ لمعرفات المفاتيح الأساسية، إذا كنت تتوقع أكثر من مليار صف، اذهب مباشرة إلى BIGINT. يكلف فقط 4 بايت إضاف��ة لكل صف (فقط 4 ميجابايت لكل مليون صف)، لكنه يوفر عليك إعادة كتابة ALTER TABLE المكلفة لجدول كبير لاحقًا.


5. التسلسلات التلقائية

(1) SERIAL مقابل IDENTITY

الطريقة الصيغة قياسي إدراج يدوي؟ موصى به
SERIAL id SERIAL PRIMARY KEY خاص بـ PG نعم توافق قديم
BIGSERIAL id BIGSERIAL PRIMARY KEY خاص بـ PG نعم توافق قديم
IDENTITY id INT GENERATED ALWAYS AS IDENTITY معيار SQL يحتاج OVERRIDING ✅ مشاريع جديدة

(2) ▶ مثال

SQL
-- عمود هوية بمعيار SQL (PostgreSQL 10+)
CREATE TABLE orders_v2 (
    id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    user_id INTEGER REFERENCES users(id),
    total DECIMAL(12, 2) DEFAULT 0
);

-- إدراج بدون تحديد id (توليد تلقائي)
INSERT INTO orders_v2 (user_id, total) VALUES (1, 99.99);

-- محاولة إدراج id يدويًا (ستفشل مع GENERATED ALWAYS)
-- INSERT INTO orders_v2 (id, user_id, total) VALUES (100, 1, 50.00);

-- استخدم GENERATED BY DEFAULT إذا كنت بحاجة لتجاوز يدوي أحيانًا
CREATE TABLE logs (
    id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    message TEXT
);

Output:

TEXT 📖 للعرض فقط
INSERT 0 1

6. الأعداد العشرية والدق��قة

(1) REAL / DOUBLE مقابل DECIMAL

النوع التخزين الدقة الأفضل لـ
REAL 4 بايت 6 أرقام معنوية الحوسبة العلمية، المستشعرات
DOUBLE PRECISION 8 بايت 15 رقمًا معنويًا الحوسبة العلمية، الإحصاء
DECIMAL(p,s) متغير دقيق المال، النسب (موصى به)
NUMERIC(p,s) متغير دقيق نفس DECIMAL

(3) ▶ مثال

SQL
-- فخ دقة العائمة: 0.1 + 0.2 != 0.3
SELECT 0.1::REAL + 0.2::REAL = 0.3::REAL AS float_equal;
-- الناتج: f (خطأ!)

-- DECIMAL لا فقدان دقة
SELECT 0.1::DECIMAL + 0.2::DECIMAL = 0.3::DECIMAL AS decimal_equal;
-- الناتج: t (صحيح!)

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(4) ▶ مثال

SQL
-- DECIMAL(الدقة, المقياس)
-- الدقة = إجمالي الأرقام، المقياس = الأرقام بعد الفاصلة العشرية
-- DECIMAL(10,2) = حتى 99,999,999.99

CREATE TABLE products_precise (
    id SERIAL PRIMARY KEY,
    name VARCHAR(200),
    price DECIMAL(10, 2) NOT NULL,       -- الحد الأقصى 99,999,999.99
    tax_rate DECIMAL(5, 4) DEFAULT 0.0875, -- 0.0875 = 8.75%
    discount NUMERIC(5, 2) DEFAULT 0.00   -- الحد الأقصى 999.99%
);

-- حسابات المال دقيقة
SELECT name,
       price,
       price * tax_rate AS tax_amount,
       price + (price * tax_rate) AS price_with_tax
FROM products_precise;

Output:

TEXT 📖 للعرض فقط
 count 
-------
     5
(1 row)
اختيار الدقة معاملات DECIMAL القيمة القصوى الأفضل لـ
تجارة إلكترونية صغيرة DECIMAL(8,2) 999,999.99 حجم يومي < 1M
تجارة إلكترونية كبيرة DECIMAL(12,2) 99,999,999,999.99 تجارة إلكترونية عالمية
عملات رقمية DECIMAL(20,8) كبير جدًا BTC دقة 8 منازل عشرية

7. أنواع السلاسل

النوع التخزين الحد الأقصى للطول الأفضل لـ
CHAR(n) طول ثابت، مبطن بمسافات n التجزئات، رموز ISO
VARCHAR(n) طول متغير n نص مع حد طول
TEXT طول متغير غير محدود نص بدون حد طول

(5) ▶ مثال

SQL
-- CHAR: طول ثابت (مبطن بمسافات)
SELECT LENGTH('abc'::CHAR(5));
-- الناتج: 5 (مبطن إلى 5 أحرف)

-- VARCHAR: طول متغير مع حد
SELECT LENGTH('abc'::VARCHAR(5));
-- الناتج: 3 (مخزن كما هو، الحد الأقصى 5)

-- TEXT: طول متغير، بلا حد
SELECT LENGTH('abc'::TEXT);
-- الناتج: 3 (بلا حد)

-- اختبار الأداء: VARCHAR و TEXT متطابقان في PG
-- (على عكس MySQL حيث VARCHAR أسرع من TEXT)

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)
💡 نصيحة: في PostgreSQL، VARCHAR و TEXT لهما أداء استعلام وتخزين متطابق. PG لا يبطئ لمجرد أن TEXT ليس له حد طول. السبب الوحيد لاختيار أحدهما على الآخر هو ما إذا كنت بحاجة لأن تفرض قاعدة البيانات حد طول.


8. أنواع التاريخ والوقت

النوع التخزين النطاق الأفضل لـ
DATE 4 بايت 4713 ق.م ~ 5874897 م تاريخ فقط (عيد ميلاد، عطلة)
TIME 8 بايت 00:00:00 ~ 24:00:00 وقت فقط (ساعات العمل)
TIMESTAMP 8 بايت 4713 ق.م ~ 294276 م تاريخ+وقت (بدون منطقة زمنية)
TIMESTAMPTZ 8 بايت نفس أعلاه تاريخ+وقت+منطقة زمنية (✅ موصى به)
INTERVAL 16 بايت ±178000000 سنة فترة زمنية

(6) ▶ مثال

SQL
-- تعيين المنطقة الزمنية إلى UTC
SET timezone = 'UTC';

-- إدراج نفس اللحظة بأنواع مختلفة
INSERT INTO test_times (ts_no_tz, ts_with_tz) VALUES
    ('2026-07-13 10:00:00', '2026-07-13 10:00:00+00');

-- التغيير إلى منطقة طوكيو الزمنية
SET timezone = 'Asia/Tokyo';

-- TIMESTAMP (بدون منطقة زمنية) يظهر نفس القيمة الحرفية
SELECT ts_no_tz FROM test_times;
-- الناتج: 2026-07-13 10:00:00 (بدون تغيير، يمكن أن يكون أي منطقة زمنية!)

-- TIMESTAMPTZ يحول إلى المنطقة الزمنية المحلية
SELECT ts_with_tz FROM test_times;
-- الناتج: 2026-07-13 19:00:00+09 (10:00 UTC = 19:00 طوكيو)

Output:

TEXT 📖 للعرض فقط
INSERT 0 1

(7) ▶ مثال

SQL
-- التاريخ والوقت الحالي
SELECT NOW();                    -- 2026-07-13 10:30:00.123456+00
SELECT CURRENT_DATE;             -- 2026-07-13
SELECT CURRENT_TIMESTAMP;        -- نفس NOW()

-- حساب التاريخ مع INTERVAL
SELECT NOW() + INTERVAL '7 days';     -- بعد أسبوع من الآن
SELECT NOW() - INTERVAL '3 months';   -- قبل 3 أشهر

-- حساب العمر
SELECT AGE(TIMESTAMP '1990-05-15');   -- 36 سنة 1 شهر 28 يوم

-- استخراج الأجزاء
SELECT EXTRACT(YEAR FROM NOW());      -- 2026
SELECT EXTRACT(MONTH FROM NOW());     -- 7
SELECT EXTRACT(DOW FROM NOW());       -- 1 (الاثنين، 0=الأحد)

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

9. الأنواع الخاصة

(1) UUID

SQL
-- تمكين إضافة uuid-ossp
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- توليد إصدارات UUID مختلفة
SELECT uuid_generate_v4();  -- UUID عشوائي (الأكثر شيوعًا)
SELECT uuid_generate_v1();  -- UUID معتمد على الوقت
إصدار UUID التوليد الأفضل لـ
v1 طابع زمني + عنوان MAC مرتب زمنيًا
v4 عشوائي معظم السيناريوهات (موصى به)
v7 طابع زمني + عشوائي (معيار جديد) مرتب زمنيًا + عشوائي

(2) INET / CIDR (عناوين الشبكة)

(8) ▶ مثال

SQL
-- INET: IP مفرد أو نطاق IP
CREATE TABLE access_log (
    id BIGSERIAL PRIMARY KEY,
    source_ip INET NOT NULL,
    access_time TIMESTAMPTZ DEFAULT NOW()
);

INSERT INTO access_log (source_ip) VALUES
    ('192.168.1.100'),
    ('10.0.0.5'),
    ('2001:db8::1');

-- استعلام: العثور على جميع IP في شبكة فرعية (مستحيل مع VARCHAR!)
SELECT source_ip FROM access_log
WHERE source_ip << '192.168.1.0/24'::INET;
-- << تعني "محتوى داخل"

Output:

TEXT 📖 للعرض فقط
INSERT 0 1
العامل المعنى مثال
<< محتوى في 192.168.1.5' << '192.168.1.0/24' = true
>> يحتوي '192.168.1.0/24' >> '192.168.1.5' = true
= يساوي '192.168.1.5'::INET = '192.168.1.5'::INET

(3) BOOLEAN

(9) ▶ مثال

SQL
-- Boolean يقبل تمثيلات متعددة
SELECT true, 't', 'true', 'yes', 'on', '1';   -- الكل = TRUE
SELECT false, 'f', 'false', 'no', 'off', '0';  -- الكل = FALSE

-- Boolean في عبارة WHERE
SELECT name FROM products WHERE is_available IS TRUE;
SELECT name FROM products WHERE is_available IS NOT FALSE;

Output:

TEXT 📖 للعرض فقط
 id | name     | value 
----+----------+-------
  1 | example  | 42
(1 row)

(4) ENUM

(10) ▶ مثال

SQL
-- إنشاء نوع تعداد (مرة واحدة، قابل لإعادة الاستخدام عبر الجداول)
CREATE TYPE order_status AS ENUM (
    'pending', 'paid', 'shipped', 'delivered', 'cancelled'
);

-- استخدام في تعريف الجدول
CREATE TABLE orders_enum (
    id SERIAL PRIMARY KEY,
    status order_status DEFAULT 'pending'
);

-- قيم التعداد يتم التحقق منها تلقائيًا
INSERT INTO orders_enum (status) VALUES ('pending');   -- موافق
-- INSERT INTO orders_enum (status) VALUES ('unknown');  -- خطأ!

Output:

TEXT 📖 للعرض فقط
INSERT 0 1
⚠️ ملاحظة: بمجرد إنشاء نوع ENUM في PG، إضافة قيم جديدة تتطلب ALTER TYPE ... ADD VALUE (مسموح داخل معاملة منذ PG 9.1). إذا كانت القيم تتغير كثيرًا، VARCHAR + قيد CHECK أكثر مرونة.


10. جدول مقارنة أنواع البيانات

الحاجة ❌ غير موصى به ✅ موصى به السبب
المال REAL / FLOAT DECIMAL(p,s) الأعداد العشرية العائمة تفقد الدقة
الطابع الزمني TIMESTAMP TIMESTAMPTZ التطبيقات العالمية تحتاج مناطق زمنية
عنوان IP VARCHAR INET INET يدعم استعلامات النطاق
نعم/لا INTEGER (0/1) BOOLEAN دلالة أوضح
نص طويل VARCHAR(9999) TEXT TEXT بلا حد ونفس الأداء
تعداد الحالة VARCHAR + CHECK ENUM أو VARCHAR+CHECK ENUM إذا كان مستقرًا، CHECK إذا كان متغيرًا
سمات مرنة أعمدة NULL كثيرة JSONB عمود واحد للحقول الديناميكية
معرف تلقائي SERIAL IDENTITY صيغة معيار SQL

11. مثال كامل: جدول يستخدم أنواعًا متعددة

SQL
-- ============================================
-- مثال كامل: جدول بجميع الأنواع الرئيسية
-- نظام جمع بيانات المستشعرات
-- ============================================

-- إنشاء نوع تعداد
CREATE TYPE sensor_status AS ENUM ('active', 'inactive', 'maintenance');

-- إنشاء جدول بأنواع بيانات متنوعة
CREATE TABLE sensors (
    -- الهوية
    id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    uuid UUID DEFAULT uuid_generate_v4() UNIQUE,

    -- النص
    name VARCHAR(100) NOT NULL,
    description TEXT,
    location_code CHAR(10),

    -- الرقمي
    latitude DECIMAL(9, 6) CHECK (latitude BETWEEN -90 AND 90),
    longitude DECIMAL(9, 6) CHECK (longitude BETWEEN -180 AND 180),
    altitude REAL,

    -- الشبكة
    ip_address INET,
    subnet CIDR,

    -- الحالة
    status sensor_status DEFAULT 'active',
    is_online BOOLEAN DEFAULT false,

    -- الوقت
    installed_at DATE,
    last_reading_at TIMESTAMPTZ,
    reading_interval INTERVAL DEFAULT INTERVAL '5 minutes',

    -- بيانات مرنة
    metadata JSONB DEFAULT '{}'::jsonb,

    -- التدقيق
    created_at TIMESTAMPTZ DEFAULT NOW()
);

-- إدراج بيانات نموذجية
INSERT INTO sensors (name, latitude, longitude, ip_address, status, installed_at, metadata)
VALUES (
    'Temperature Sensor A1',
    35.6762, 139.6503,
    '192.168.1.50',
    'active',
    '2025-01-15',
    '{"model": "TX-200", "unit": "celsius", "range_min": -40, "range_max": 85}'::jsonb
);

-- استعلام بعوامل خاصة بالنوع
SELECT name, ip_address, metadata->>'model' AS model
FROM sensors
WHERE ip_address << '192.168.1.0/24'::INET
  AND status = 'active';

❓ أسئلة شائعة

س ما الفرق بين DECIMAL و NUMERIC؟
ج في PostgreSQL، DECIMAL و NUMERIC متكافئان تمامًا وقابلان للتبادل. يميز معيار SQL بينهما بشكل طفيف، لكن تنفيذ PG متطابق. DECIMAL موصى به (أكثر بديهية).
س ماذا لو تخطى تسلسل عمود SERIAL أرقامًا؟
ج يستخدم SERIAL كائن تسلسل؛ بعد فشل INSERT أو التراجع عنه، لا يتم التراجع عن قيمة التسلسل (هذا بالتصميم، لضمان أمان التزامن). الفجوات طبيعية ولا تؤثر على الوظيفة. إذا كنت بحاجة▶�قيم متتالية، تعامل معها في طبقة التطبيق بدلاً من الاعتماد على التسلسل.
س هل تغيير VARCHAR(50) إلى VARCHAR(100) يقفل الجدول؟
ج في PostgreSQL، زيادة طول VARCHAR لا تقفل الجدول (لا إعادة كتابة بيانات) وتكتمل فورًا. تقليل الطول أو تغيير النوع هو ما يقفل الجدول.
س أيهما أختار، JSON أم JSONB؟
ج تقريبًا دائمًا JSONB. JSONB مخزن كثنائي ويدعم الاستعلامات المفهرسة، لذا فهو سريع. JSON مخزن كنص ويجب إعادة تحليله في كل استعلام. الحالة الوحيدة لـ JSON: عندما تحتاج للحفاظ على ترتيب المسافات البيضاء/المفاتيح للإدخال (مثلاً، سجلات التدقيق).
س لماذا يوصى بـ TIMESTAMPTZ على TIMESTAMP؟
ج TIMESTAMPTZ يحول إلى UTC عند التخزين ويعود إلى المنطقة الزمنية للعميل عند القراءة. هذا يعني أن المستخدمين العالميين يرون وقتهم المحلي بدون ارتباك. TIMESTAMP يخزن ويعيد تمامًا ما تعطيه، وهو غامض للتطبيقات عبر المناطق الزمنية.
س هل خلط أنواع بيانات متعددة في جدول واحد يضر بالأداء؟
ج لا. PG يخزن معلومات النوع لكل عمود ويقرأ فقط الأعمدة التي يحتاجها. استخدام الأنواع المخصصة بشكل مناسب (مثلاً، INET لعناوين IP) يحسن أداء الاستعلام فعليًا، لأن عوامل النوع يمكنها استخدام الفهارس.

📖 ملخص


📝 تمارين

  1. أساسي (★): أنشئ جدول countries مع: id (SERIAL مفتاح أساسي)، name (VARCHAR(100))، iso_code (CHAR(2))، population (BIGINT)، gdp DECIMAL(15,2)، is_developed (BOOLEAN). أدرج 3 صفوف اختبار.

  2. متوسط (★★): أنشئ جدول server_logs مع: id (BIGINT IDENTITY مفتاح أساسي)، source_ip (INET)، request_time (TIMESTAMPTZ)، response_time_ms (INTEGER)، is_error (BOOLEAN)، metadata (JSONB). أدرج سجلي سجل، ثم استعلم عن جميع السجلات من شبكة 10.0.0.0/8.

  3. تحدي (★★★): صمم جدول financial_transactions يتعامل مع عملات متعددة (USD/EUR/JPY/CNY) بدقات مبالغ مختلفة (USD/EUR: منزلتان عشريتان، JPY: 0 منازل عشرية، CNY: منزلتان عشريتان). نفذه باستخدام DECIMAL + قيود CHECK بحيث تتطلب العملات المختلفة مقاييس عشرية مختلفة. اكتب CREATE TABLE SQL بالإضافة إلى 3 أمثلة INSERT لعملات مختلفة.

Web-Tutorial.com

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

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

100%