الصفوف الزمنية والمُدارة بالإصدارات
استعلامات الوقت الصالح والبيانات كما كانت في وقت محدد
الصفوف الزمنية والمُدارة بالإصدارات درس مجاني في SQL Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في SQL Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة SQL Academy 4 دروس في المجموع.
ما هي الجداول الزمنية؟
تتيح لك الجداول الزمنية تتبع كيفية تغير البيانات بمرور الزمن. فبدلًا من الكتابة فوق الصف عند حدوث تغيير، يحتفظ الجدول الزمني بكل إصدار من ذلك الصف، مع وسم كل إصدار بالفترة التي كان ساريًا فيها.
هناك مفهومان أساسيان: زمن السريان، أي وقت صحة الحقيقة في العالم الحقيقي، وزمن المعاملة، أي وقت تسجيل قاعدة البيانات للحقيقة. ويؤدي الجمع بينهما إلى جدول ثنائي الزمن بالكامل.
زمن السريان مقابل زمن المعاملة
يمثل زمن السريان الوقت الذي تكون فيه الحقيقة صحيحة في العالم الحقيقي، مثل راتب موظف سار من 2020-01-01 إلى 2022-06-30. أما زمن المعاملة فهو وقت إدراج صف قاعدة البيانات أو انتهاء سريانه. ويجيب المفهومان معًا عن سؤالين: ما الذي كان صحيحًا؟ ومتى علمنا به؟
تبدأ معظم حالات الاستخدام العملية بتتبع زمن السريان، ويمكنك تنفيذ ذلك يدويًا باستخدام العمودين valid_from وvalid_to.
إنشاء جدول بزمن السريان
إن أبسط طريقة لتخزين الصفوف ذات الإصدارات هي إضافة عمودي طابع زمني هما valid_from وvalid_to. وتعني قيمة NULL في valid_to، أو قيمة حارسة بعيدة في المستقبل مثل 9999-12-31، أن الصف نشط حاليًا.
CREATE TABLE employee_salary (
id SERIAL PRIMARY KEY,
employee_id INT NOT NULL,
salary NUMERIC(12, 2) NOT NULL,
valid_from DATE NOT NULL,
valid_to DATE
);
INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES
(1, 50000, '2020-01-01', '2022-06-30'),
(1, 60000, '2022-07-01', NULL);الاستعلام عن الإصدار الحالي
للعثور على الصف النشط حاليًا لكل موظف، صفِّ الصفوف التي تكون فيها قيمة valid_to IS NULL، أي غير محددة النهاية، أو التي يقع تاريخ اليوم ضمن نطاق سريانها. ويبسّط استخدام قيمة حارسة مثل '9999-12-31' مقارنات النطاق.
SELECT employee_id, salary
FROM employee_salary
WHERE valid_to IS NULL
ORDER BY employee_id;الاستعلام عند نقطة زمنية
يسأل الاستعلام عند نقطة زمنية: ما البيانات التي كانت موجودة في وقت محدد؟ صفِّ الصفوف التي يقع فيها الطابع الزمني المحدد ضمن فترة السريان. وهذه إحدى أقوى ميزات الجداول الزمنية.
-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_from, valid_to
FROM employee_salary
WHERE employee_id = 1
AND valid_from <= '2021-03-15'
AND (valid_to IS NULL OR valid_to > '2021-03-15');تحديث صف ذي إصدارات
عند تغير حقيقة ما، لا تُجرِ UPDATE على الصف الحالي مباشرةً. بل تنهي سريان الصف الحالي بتعيين قيمة valid_to له، ثم تُدرج صفًا جديدًا بالقيمة الجديدة باستخدام INSERT. ويحافظ ذلك على السجل الكامل.
-- Employee 1 gets a raise effective 2023-01-01
BEGIN;
-- Close the current open row
UPDATE employee_salary
SET valid_to = '2022-12-31'
WHERE employee_id = 1
AND valid_to IS NULL;
-- Insert the new version
INSERT INTO employee_salary (employee_id, salary, valid_from, valid_to)
VALUES (1, 72000, '2023-01-01', NULL);
COMMIT;استخدام daterange لفترات السريان
يمثل نوع daterange في PostgreSQL فترة السريان في عمود واحد بطريقة أنيقة. ويمكنك استخدام العامل @> (يحتوي) للتحقق مما إذا كان تاريخ ما يقع ضمن النطاق، وإضافة قيد استبعاد لمنع تداخل الفترات للكيان نفسه.
CREATE TABLE employee_salary_v2 (
id SERIAL PRIMARY KEY,
employee_id INT NOT NULL,
salary NUMERIC(12, 2) NOT NULL,
valid_period DATERANGE NOT NULL,
EXCLUDE USING GIST (employee_id WITH =, valid_period WITH &&)
);
INSERT INTO employee_salary_v2 (employee_id, salary, valid_period)
VALUES
(1, 50000, '[2020-01-01, 2022-07-01)'),
(1, 60000, '[2022-07-01, infinity)');استعلام عند نقطة زمنية باستخدام daterange
باستخدام أسلوب daterange، يصبح الاستعلام عند نقطة زمنية واضحًا جدًا. يتحقق العامل @> من أن التاريخ المحدد موجود ضمن النطاق، ويتولى تلقائيًا التعامل مع الحدين الأدنى والأقصى.
-- What was employee 1's salary on 2021-03-15?
SELECT employee_id, salary, valid_period
FROM employee_salary_v2
WHERE employee_id = 1
AND valid_period @> '2021-03-15'::date;الجداول ذات الإصدار النظامي (معيار SQL)
قدّم معيار SQL:2011 الجداول الزمنية ذات الإصدار النظامي. وتدير قاعدة البيانات تلقائيًا عمودي زمن المعاملة row_start وrow_end. في PostgreSQL تحاكي هذا السلوك، بينما يكون مدمجًا في SQL Server وMariaDB باستخدام SYSTEM VERSIONING.
يوضح المثال أدناه صيغة SQL Server / MariaDB كمرجع للمفهوم.
-- SQL Server / MariaDB syntax (reference)
CREATE TABLE dbo.Product (
ProductID INT PRIMARY KEY,
Name VARCHAR(100),
Price DECIMAL(10,2),
SysStart DATETIME2 GENERATED ALWAYS AS ROW START,
SysEnd DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (SysStart, SysEnd)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Product_History));الربط الزمني: مواءمة جدولين عبر الزمن
يتمثل أحد التحديات الشائعة في ربط جدولين زمنيين وفق فترات زمنية متطابقة. فعلى سبيل المثال، يمكنك ربط رواتب الموظفين بتعيينات الأقسام عندما يكون لكل منهما فترات سريان. ويتم الربط باستخدام مفتاح الكيان وشرط التداخل، عبر && على النطاقات أو مقارنات التاريخ الصريحة.
CREATE TABLE dept_assignment (
employee_id INT,
department VARCHAR(50),
valid_period DATERANGE
);
INSERT INTO dept_assignment VALUES
(1, 'Engineering', '[2020-01-01, infinity)'),
(1, 'Marketing', '[2019-01-01, 2020-01-01)');
-- Periods where employee 1 was in Engineering AND had salary > 55000
SELECT s.salary, d.department,
s.valid_period * d.valid_period AS overlap_period
FROM employee_salary_v2 s
JOIN dept_assignment d
ON s.employee_id = d.employee_id
AND s.valid_period && d.valid_period
WHERE s.employee_id = 1
AND s.salary > 55000;منع الفجوات والتداخلات
هناك مشكلتان شائعتان في جودة البيانات داخل الجداول الزمنية: الفجوات، وهي الفترات التي لا يوجد فيها سجل، والتداخلات، وهي وجود صفين ساريين في الوقت نفسه. ويمنع قيد الاستبعاد باستخدام && التداخلات على مستوى قاعدة البيانات. أما اكتشاف الفجوات فيتطلب التحقق من التغطية المفقودة باستخدام استعلام.
-- Find gaps in salary history for employee 1
-- (periods where upper(prev) < lower(next))
SELECT
upper(a.valid_period) AS gap_start,
lower(b.valid_period) AS gap_end
FROM employee_salary_v2 a
JOIN employee_salary_v2 b
ON a.employee_id = b.employee_id
AND upper(a.valid_period) < lower(b.valid_period)
WHERE a.employee_id = 1
AND NOT EXISTS (
SELECT 1 FROM employee_salary_v2 c
WHERE c.employee_id = 1
AND lower(c.valid_period) > upper(a.valid_period)
AND lower(c.valid_period) < lower(b.valid_period)
)
ORDER BY gap_start;اختبار المعرفة
اختبر مدى فهمك للجداول الزمنية والاستعلامات عند نقطة زمنية.
مراجعة: الصفوف الزمنية وذات الإصدارات
تعلمت في هذا الدرس كيفية نمذجة البيانات المتغيرة بمرور الوقت باستخدام أعمدة زمن السريان ونوع daterange في PostgreSQL. أهم النقاط:
- لا تكتب فوق الصفوف التاريخية أبدًا، بل أنهِ سريان الصف القديم وأدرج إصدارًا جديدًا.
- استخدم الاستعلامات عند نقطة زمنية (
valid_from <= target AND valid_to > target) لاسترجاع البيانات في أي لحظة سابقة. - يجعل نوع
daterangeمع العامل@>الاستعلامات الزمنية موجزة وسهلة القراءة. - تفرض قيود الاستبعاد على
&&(تداخل النطاقات) سلامة البيانات على مستوى قاعدة البيانات. - تعمل الروابط الزمنية على مواءمة سجلين تاريخيين من خلال تقاطع فترات سريانهما.
تشكل هذه الأنماط أساس Event Sourcing وتسجيل التدقيق وأي نظام تكون فيه الدقة التاريخية مهمة.
الأسئلة الشائعة
هل درس «الصفوف الزمنية والمُدارة بالإصدارات» مجاني؟
نعم — نص درس «الصفوف الزمنية والمُدارة بالإصدارات» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة SQL Academy، انتقل إلى CoddyKit PRO. تتضمن دورة SQL Academy 4 دروس في المجموع.
ماذا ستتعلم في «الصفوف الزمنية والمُدارة بالإصدارات»؟
استعلامات الوقت الصالح والبيانات كما كانت في وقت محدد تتمرن على SQL Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ SQL Academy؟
لا تُشترط خبرة سابقة. SQL Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «الصفوف الزمنية والمُدارة بالإصدارات»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس SQL Academy هذا؟
نعم. كل درس في SQL Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- لماذا نحتفظ بالسجل التاريخي
- جداول الأحداث ذات الإلحاق فقط
- الصفوف الزمنية والمُدارة بالإصدارات
- إعادة بناء الحالة من الأحداث