مقدمة
عند العمل مع قواعد البيانات العلاقوية ولغة الاستعلام الهيكلية (SQL)، قد تحتاج في بعض الأحيان إلى العمل مع قيم تمثل تواريخ معينة أو أوقات. على سبيل المثال، قد تحتاج إلى حساب إجمالي الساعات المستغرقة في نشاط معين، أو ربما تحتاج إلى تعديل قيم التاريخ أو الوقت باستخدام العمليات الرياضية والدوال التجميعية لحساب مجموعها أو متوسطها.
في هذا البرنامج التعليمي، ستتعلم كيفية استخدام التواريخ والأوقات في SQL. ستبدأ بأداء العمليات الحسابية واستخدام مختلف الدوال مع التواريخ والأوقات باستخدام البيان SELECT
فقط. ثم ستمارس من خلال تشغيل استعلامات على بيانات عينة، وستتعلم كيفية تنفيذ الدالة CAST
لجعل الناتج أكثر قابلية للقراءة.
المتطلبات المسبقة
لإكمال هذا البرنامج التعليمي، ستحتاج إلى:
- A server running Ubuntu 20.04, with a non-root user with
sudo
administrative privileges and firewall enabled. Follow our Initial Server Setup with Ubuntu 20.04 to get started. - تثبيت MySQL وتأمينه على الخادم. اتبع دليلنا كيفية تثبيت MySQL على أوبونتو 20.04 لإعداد هذا. يفترض هذا الدليل أنك قمت أيضًا بإعداد مستخدم MySQL غير الجذر، كما هو موضح في الخطوة 3 من هذا الدليل.
ملاحظة: يرجى ملاحظة أن العديد من أنظمة إدارة قواعد البيانات العلاقية تستخدم تنفيذات SQL الفريدة الخاصة بها. على الرغم من أن الأوامر الموضحة في هذا البرنامج التعليمي ستعمل على معظم أنظمة إدارة قواعد البيانات العلاقية، قد تختلف الصيغة الدقيقة أو الإخراج إذا قمت باختبارها على نظام غير MySQL.
لممارسة استخدام التاريخ والوقت في هذا البرنامج التعليمي، ستحتاج إلى قاعدة بيانات وجدول محملين ببيانات عينية. إذا لم يكن لديك واحد جاهزًا للإدراج، يمكنك قراءة القسم التالي الاتصال بـ MySQL وإعداد قاعدة بيانات عينية لتعلم كيفية إنشاء قاعدة بيانات وجدول. سيشير هذا البرنامج التعليمي إلى قاعدة البيانات والجدول العينيين طواله.
الاتصال بـ MySQL وإعداد قاعدة بيانات عينية
إذا كانت قاعدة بيانات SQL الخاصة بك تعمل على خادم بعيد، قم بالاتصال بـ SSH إلى خادمك من جهازك المحلي:
ثم، افتح موجه MySQL، مستبدلاً sammy
بمعلومات حساب مستخدم MySQL الخاصة بك:
أنشئ قاعدة بيانات بالاسم datetimeDB
:
إذا تم إنشاء قاعدة البيانات بنجاح، ستتلقى الإخراج التالي:
OutputQuery OK, 1 row affected (0.01 sec)
لتحديد قاعدة البيانات datetimeDB
، قم بتشغيل البيان التالي باستخدام الأمر USE
:
OutputDatabase changed
بعد اختيار قاعدة البيانات، أنشئ جدولًا داخلها. في مثال البرنامج التعليمي هذا، سنقوم بإنشاء جدول يحتوي على نتائج سباقات لمتسابقين اثنين في مختلف السباقات التي شاركوا فيها على مدار السنة. سيحتوي هذا الجدول على سبعة أعمدة تالية:
race_id
: يعرض قيمًا من نوع البياناتint
ويعمل كمفتاح أساسي للجدول، مما يعني أن كل قيمة في هذه العمود ستعمل كمعرف فريد للصف الخاص به.runner_name
: يستخدم نوع البياناتvarchar
مع حد أقصى للأحرف يبلغ 30 حرفًا لأسماء المتسابقين الاثنين، بولت وفيليكس.race_name
: يحتوي على أنواع السباقات باستخدام نوع البياناتvarchar
بحد أقصى للأحرف يبلغ 20 حرفًا.start_day
: يستخدم نوع البياناتDATE
لتتبع تاريخ سباق معين حسب السنة، والشهر، واليوم. يتبع هذا النوع من البيانات المعلمات التالية: أربعة أرقام للسنة، وحد أقصى للأرقام للشهر واليوم (YYYY-MM-DD).start_time
: يمثل وقت بدء السباق باستخدام نوع البياناتTIME
بالساعات والدقائق والثواني (HH:MM:SS). يتبع هذا النوع من البيانات تنسيق الساعة العسكري بتصميم 24 ساعة، مثل15:00
للمكافئة للساعة 3:00 مساءً.total_miles
: يعرض إجمالي الميلات لكل سباق باستخدام نوع البياناتdecimal
حيث أن العديد من الأميال الإجمالية لكل سباق ليست أعدادًا صحيحة. في هذه الحالة، يُحددdecimal
دقة ثلاثة أرقام مع درجة واحدة، مما يعني أن أي قيم في هذا العمود يمكن أن تحتوي على ثلاثة أرقام، مع واحدة من تلك الأرقام تكون على يمين الفاصلة العشرية.end_time
: يستخدم نوع البياناتTIMESTAMP
لتتبع أوقات الجري عند نهاية السباق. هذا النوع من البيانات يجمع بين التاريخ والوقت في سلسلة واحدة، وتنسيقه هو مزيج من تنسيقاتDATE
وTIME
: (YYYY-MM-DD HH:MM:SS
).
قم بإنشاء الجدول عن طريق تشغيل أمر CREATE TABLE
:
ثم أدخل بعض البيانات العينية في الجدول الفارغ:
OutputQuery OK, 10 rows affected (0.00 sec)
Records: 10 Duplicates: 0 Warnings: 0
بمجرد إدخال البيانات، أنت جاهز للبدء في ممارسة بعض العمليات الحسابية والوظائف مع التاريخ والوقت في SQL.
استخدام الحسابات مع التواريخ والأوقات
في SQL، يمكنك التلاعب بقيم التاريخ والوقت باستخدام التعبيرات الرياضية. كل ما يلزم هو المشغل الرياضي والقيم التي ترغب في حسابها.
كمثال، فلنقل أنك تريد العثور على تاريخ معين يأتي بعد عدد معين من الأيام من تاريخ آخر. تأخذ الاستعلام التالي قيمة تاريخ واحدة (2022-10-05
) ويضيف 17
إليها لإرجاع قيمة التاريخ التي تلي التاريخ المحدد في الاستعلام. يُلاحظ أن هذا المثال يحدد 2022-10-05
كقيمة DATE
لضمان عدم تفسير نظام إدارة قواعد البيانات لها على أنها سلسلة أو نوع بيانات آخر:
Output+----------+
| new_date |
+----------+
| 20221022 |
+----------+
1 row in set (0.01 sec)
كما يشير هذا الإخراج، فإن 17 يومًا بعد 2022-10-05
هو 2022-10-22
، أو 22 أكتوبر 2022.
كمثال آخر، فلنقل أنك ترغب في حساب إجمالي الساعات بين وقتين مختلفين. يمكنك فعل ذلك عن طريق طرح الوقتين من بعضهما البعض. في الاستعلام التالي، 11:00
هو قيمة الوقت الأولى و 3:00
هي قيمة الوقت الثانية. هنا ستحتاج إلى تحديد أن كلتاهما قيم TIME
من أجل إرجاع الفرق بالساعات:
Output+-----------+
| time_diff |
+-----------+
| 80000 |
+-----------+
1 row in set (0.00 sec)
يخبرك هذا الإخراج أن الفرق بين 11:00 و 3:00 هو 80000
، أو 8 ساعات.
الآن قم بممارسة استخدام الحسابات الحسابية على معلومات التاريخ والوقت من البيانات العينية. للاستعلام الأول، قم بحساب الوقت الإجمالي الذي استغرقه العدائين لإنهاء كل سباق عن طريق طرح end_time
من start_time
:
Output+-------------+---------------+----------------+
| runner_name | race_name | total_time |
+-------------+---------------+----------------+
| bolt | 1600_meters | 20220918000630 |
| bolt | 5K | 20221019002231 |
| bolt | 10K | 20221120003805 |
| bolt | half_marathon | 20221221013904 |
| bolt | full_marathon | 20230122032310 |
| felix | 1600_meters | 20220918000715 |
| felix | 5K | 20221019003050 |
| felix | 10K | 20221120011017 |
| felix | half_marathon | 20221221021157 |
| felix | full_marathon | 20230122040210 |
+-------------+---------------+----------------+
10 rows in set (0.00 sec)
ستلاحظ أن هذا الإخراج في العمود total_time
طويل وصعب القراءة. لاحقًا، سنقدم كيفية استخدام وظيفة CAST
لتحويل قيم البيانات هذه بحيث تكون أوضح للقراءة.
الآن، إذا كنت مهتمًا فقط بأداء كل من المتسابقين في السباقات الطويلة، مثل النصف ماراثون والماراثون الكامل، يمكنك استعلام بياناتك لاسترداد تلك المعلومات. لهذا الاستعلام، اطرح end_time
من start_time
، واضيق نطاق نتائجك باستخدام الشرط WHERE
لاسترداد البيانات حيث كانت total_miles
أكبر من 12:
Output+-------------+---------------+-------------------+
| runner_name | race_name | half_full_results |
+-------------+---------------+-------------------+
| bolt | half_marathon | 20221221013904 |
| bolt | full_marathon | 20230122032310 |
| felix | half_marathon | 20221221021157 |
| felix | full_marathon | 20230122040210 |
+-------------+---------------+-------------------+
4 rows in set (0.00 sec)
في هذا القسم، قمت بإجراء بعض العمليات الحسابية على التواريخ والأوقات باستخدام البيانات العينية لأغراض عملية. فيما بعد، ستتدرب على استعلامات باستخدام مجموعة متنوعة من وظائف التاريخ والوقت.
استخدام وظائف التاريخ والوقت وتعابير الفاصلة الزمنية
هناك عدة وظائف يمكن استخدامها للعثور على قيم التاريخ والوقت ومعالجتها في SQL. تُستخدم وظائف SQL عادةً لمعالجة أو تلاعب البيانات، وتتوفر الوظائف المتاحة اعتمادًا على تنفيذ SQL. ومع ذلك، يُسمح في معظم تنفيذات SQL بالعثور على التاريخ والوقت الحاليين عن طريق الاستعلام عن قيم current_date
و current_time
.
للعثور على تاريخ اليوم، على سبيل المثال، فإن الصيغة قصيرة ومتكونة فقط من البيان SELECT
ووظيفة current_date
كما في ما يلي:
Output+--------------+
| current_date |
+--------------+
| 2022-02-15 |
+--------------+
1 row in set (0.00 sec)
باستخدام نفس الصيغة، يمكنك العثور على الوقت الحالي باستخدام وظيفة current_time
:
Output+--------------+
| current_time |
+--------------+
| 17:10:20 |
+--------------+
1 row in set (0.00 sec)
إذا كنت تفضل الاستعلام عن التاريخ والوقت في الناتج، استخدم وظيفة current_timestamp
:
Output+---------------------+
| current_timestamp |
+---------------------+
| 2022-02-15 19:09:58 |
+---------------------+
1 row in set (0.00 sec)
يمكنك استخدام وظائف التاريخ والوقت مثل هذه داخل الوظائف الحسابية بشكل مشابه للقسم السابق. على سبيل المثال، إذا كنت ترغب في معرفة التاريخ قبل 11 يومًا من تاريخ اليوم. في هذه الحالة، يمكنك استخدام نفس بنية الصيغة التي استخدمتها سابقًا للاستعلام عن وظيفة current_date
ثم طرح 11
منها للعثور على التاريخ منذ 11 يومًا:
Output+-------------------+
| current_date - 11 |
+-------------------+
| 20220206 |
+-------------------+
1 row in set (0.01 sec)
كما يشير هذا الإخراج، فقد كان قبل 11 يومًا من current_date
(في وقت كتابة هذا النص) بتاريخ 2022-02-06
، أو 6 فبراير 2022. جرب الآن تشغيل نفس العملية هذه، ولكن استبدل current_date
بوظيفة current_time
:
Output+-------------------+
| current_time - 11 |
+-------------------+
| 233639 |
+-------------------+
1 row in set (0.00 sec)
يظهر هذا الإخراج أنه عندما تقوم بطرح 11
من قيمة current_time
، يتم طرح 11 ثانية. فإن العملية التي قمت بها سابقًا باستخدام وظيفة current_date
فهي تفسر 11
على أنها أيام، لا ثواني. يمكن أن يكون هذا التناقض في كيفية تفسير الأرقام عند العمل مع وظائف التاريخ والوقت مربكًا. بدلاً من ذلك، بدلاً من أن تطلب منك تلاعب القيم التاريخية والزمنية باستخدام الحسابات مثل هذه، تتيح لك العديد من نظم إدارة قواعد البيانات أن تكون أكثر وضوحًا من خلال استخدام تعبيرات INTERVAL
.
تسمح تعبيرات INTERVAL
لك بالعثور على التاريخ أو الوقت قبل أو بعد فترة زمنية محددة من تعبير تاريخ أو وقت معين. يجب أن تأخذ الصيغة التالية:
INTERVAL value unit
على سبيل المثال، للعثور على التاريخ بعد خمسة أيام من الآن، يمكنك تشغيل الاستعلام التالي:
يعثر هذا المثال على قيمة current_date
، ثم يضيف تعبير الفاصلة الزمنية INTERVAL '5' DAY
إليها. يعيد هذا التاريخ خمسة أيام من الآن:
Output+-------------------+
| 5_days_from_today |
+-------------------+
| 2022-03-06 |
+-------------------+
1 row in set (0.00 sec)
هذا أقل غموضًا بكثير من الاستعلام التالي، الذي ينتج نتائج مماثلة، على الرغم من أنها ليست متطابقة تمامًا:
Output+-------------------+
| 5_days_from_today |
+-------------------+
| 20220306 |
+-------------------+
1 row in set (0.00 sec)
يرجى ملاحظة أنه يمكنك أيضًا طرح فترات زمنية من التواريخ أو الأوقات للعثور على القيم من قبل قيمة التاريخ المحددة:
Output+--------------+
| 7_months_ago |
+--------------+
| 2021-08-01 |
+--------------+
1 row in set (0.00 sec)
الوحدات المتاحة لك لاستخدامها في تعابير INTERVAL
تعتمد على اختيار نظام إدارة قاعدة البيانات الخاص بك، على الرغم من أن معظمها سيكون لديه خيارات مثل HOUR
، MINUTE
، و SECOND
:
Output+------------------+---------------+---------------------+
| 6_hours_from_now | 5_minutes_ago | 20_seconds_from_now |
+------------------+---------------+---------------------+
| 07:51:43 | 01:46:43 | 01:52:03.000000 |
+------------------+---------------+---------------------+
1 row in set (0.00 sec)
الآن بعد أن تعرفت على تعابير الفاصلة الزمنية وبعض وظائف التاريخ والوقت، استمر في ممارسة العمل مع البيانات العينية التي أدخلتها في الخطوة الأولى.
استخدام CAST ووظائف التجميع مع التاريخ والوقت
تذكر من المثال الثالث في القسم استخدام الحساب مع التواريخ والأوقات، عندما قمت بتشغيل الاستعلام التالي لطرح end_time
من start_time
لحساب عدد الساعات الكلية التي قام بها كل عداء في كل سباق. ومع ذلك، كانت النتيجة عبارة عن عمود يحتوي على إخراج طويل جدًا، الذي يتبع نوع البيانات TIMESTAMP
الذي تم تعيينه في الجدول:
Output+-------------+---------------+----------------+
| runner_name | race_name | total_time |
+-------------+---------------+----------------+
| bolt | 1600_meters | 20220918000630 |
| bolt | 5K | 20221019002231 |
| bolt | 10K | 20221120003805 |
| bolt | half_marathon | 20221221013904 |
| bolt | full_marathon | 20230122032310 |
| felix | 1600_meters | 20220918000715 |
| felix | 5K | 20221019003050 |
| felix | 10K | 20221120011017 |
| felix | half_marathon | 20221221021157 |
| felix | full_marathon | 20230122040210 |
+-------------+---------------+----------------+
10 rows in set (0.00 sec)
بما أنك تقوم بعملية باستخدام عمودين لهما أنواع بيانات مختلفة (end_time
الذي يحمل قيم TIMESTAMP
و start_time
الذي يحمل قيم TIME
)، فإن قاعدة البيانات لا تعرف أي نوع بيانات يجب استخدامه عند طباعة نتيجة العملية. بدلاً من ذلك، تحول كل قيمة إلى أعداد صحيحة حتى تتمكن من إجراء العملية، مما يؤدي إلى الأرقام الطويلة في عمود total_time
.
لتسهيل قراءة وتفسير هذه البيانات، يمكنك استخدام وظيفة CAST
لتحويل هذه القيم الصحيحة الطويلة إلى نوع البيانات TIME
. للقيام بذلك، ابدأ بكتابة CAST
وبعدها مباشرة قوسًا مفتوحًا، والقيم التي تريد تحويلها، ثم كلمة المفتاح AS
ونوع البيانات الذي تريد تحويله إليه.
الاستعلام التالي مطابق للمثال السابق، ولكنه يستخدم وظيفة CAST
لتحويل عمود total_time
إلى نوع البيانات time
:
Output+-------------+---------------+------------+
| runner_name | race_name | total_time |
+-------------+---------------+------------+
| bolt | 1600_meters | 00:06:30 |
| bolt | 5K | 00:22:31 |
| bolt | 10K | 00:38:05 |
| bolt | half_marathon | 01:39:04 |
| bolt | full_marathon | 03:23:10 |
| felix | 1600_meters | 00:07:15 |
| felix | 5K | 00:30:50 |
| felix | 10K | 01:10:17 |
| felix | half_marathon | 02:11:57 |
| felix | full_marathon | 04:02:10 |
+-------------+---------------+------------+
10 rows in set (0.00 sec)
قامت CAST
بتحويل قيم البيانات إلى نوع TIME
في هذا الإخراج، مما جعلها أكثر سهولة في القراءة والفهم.
الآن، دعنا نستخدم بضعة وظائف تجميع مع وظيفة CAST
للعثور على أقصر وأطول وأجمالي نتائج الزمن لكل عداء. أولاً، اطلب الحد الأدنى (أو الأقصر) للزمن المستغرق باستخدام وظيفة التجميع MIN
. مرة أخرى، سترغب في استخدام CAST
لتحويل قيم البيانات TIMESTAMP
إلى قيم بيانات TIME
للوضوح. يرجى ملاحظة أنه عند استخدام وظيفتين مثل هذا المثال، يتطلب اثنان من الأقواس وتضمين الحسابات لإجمالي الساعات (end_time - start_time
) يجب أن تكون متداخلة داخل أحدهما. وأخيرًا، أضف شرط GROUP BY
لتنظيم هذه القيم استنادًا إلى عمود runner_name
بحيث يقدم الناتج نتائج سباق العداءين:
Output+-------------+----------+
| runner_name | min_time |
+-------------+----------+
| bolt | 00:06:30 |
| felix | 00:07:15 |
+-------------+----------+
2 rows in set (0.00 sec)
يعرض هذا الناتج أقصر وقت تشغيل لكل عداء، في هذه الحالة الحد الأدنى ستة دقائق و 30 ثانية لـ بولت، وسبع دقائق و 15 ثانية لـ فيليكس.
المرة القادمة، ابحث عن أطول وقت تشغيل لكل عداء. يمكنك استخدام نفس الصيغة كما في الاستعلام السابق، ولكن هذه المرة استبدل MIN
بـ MAX
:
Output+-------------+----------+
| runner_name | max_time |
+-------------+----------+
| bolt | 03:23:10 |
| felix | 04:02:10 |
+-------------+----------+
2 rows in set (0.00 sec)
يخبرنا هذا الناتج بأن أطول وقت تشغيل لبولت كان مجموعه ثلاث ساعات و 23 دقيقة و 10 ثوانٍ؛ ولفيليكس كان مجموعه أربع ساعات و 2 دقيقة و 10 ثوانٍ.
الآن دعونا نستعلم عن بعض المعلومات على مستوى عالٍ حول إجمالي عدد الساعات التي قضاها كل من العدائين في الركض. لهذا الاستعلام، قم بدمج وظيفة الجمع SUM
للعثور على إجمالي المدة بناءً على end_time - start_time
، واستخدم CAST
لتحويل قيم البيانات تلك إلى TIME
. ولا تنسى تضمين GROUP BY
لتنظيم القيم لنتائج العدائين:
Output+-------------+-------------+
| runner_name | total_hours |
+-------------+-------------+
| bolt | 52880 |
| felix | 76149 |
+-------------+-------------+
2 rows in set (0.00 sec)
بشكل مثير للاهتمام، تظهر هذه النتائج تفسيرًا لـ MySQL، الذي يقوم في الواقع بحساب الوقت الإجمالي كأعداد صحيحة. إذا قرأنا هذه النتائج على أنها وقت، فإن الوقت الإجمالي لـ بولت ينقسم إلى خمس ساعات و28 دقيقة و80 ثانية؛ ووقت فيليكس ينقسم إلى سبع ساعات و61 دقيقة و49 ثانية. كما يمكنك أن تلاحظ، فإن هذا تقسيم الوقت لا يبدو منطقيًا، مما يشير إلى أنه يتم حسابه كعدد صحيح وليس وقت. إذا جربت هذا في نظام إدارة قواعد البيانات المختلف مثل PostgreSQL، على سبيل المثال، فإن نفس الاستعلام سيبدو مختلفًا قليلا:
Output runner_name | total_hours
-------------+-------------
felix | 10:01:44
bolt | 06:09:20
(2 rows)
في هذه الحالة، يفسر الاستعلام في PostgreSQL القيم على أنها وقت ويحسبها على هذا النحو، بحيث ينقسم نتائج فيليكس إلى مجموع يبلغ 10 ساعات ودقيقة و44 ثانية؛ وينقسم وقت بولت إلى ست ساعات وتسع دقائق و20 ثانية. هذا هو مثال على كيفية قد تفسر مختلف تنفيذات أنظمة إدارة قواعد البيانات قيم البيانات بشكل مختلف حتى لو كانت تستخدم نفس الاستعلام ومجموعة بيانات.
الاستنتاج
فهم كيفية استخدام التاريخ والوقت في SQL مفيد عند الاستعلام عن نتائج محددة مثل الدقائق، والثواني، والساعات، والأيام، والأشهر، والسنوات؛ أو مزيج من كل ذلك. بالإضافة إلى ذلك، هناك العديد من الوظائف المتاحة للتواريخ والأوقات التي تجعل من السهل العثور على قيم معينة، مثل التاريخ الحالي أو الوقت. في حين استخدم هذا البرنامج التعليمي فقط الجمع والطرح الحسابي على التواريخ والأوقات في SQL، يمكنك استخدام قيم التاريخ والوقت مع أي تعبير رياضي. تعرف على المزيد من دليلنا على التعبيرات الرياضية والوظائف التجميعية وجربها مع استعلامات التاريخ والوقت الخاصة بك.
Source:
https://www.digitalocean.com/community/tutorials/how-to-work-with-dates-and-times-in-sql