הקדמה
כאשר אתה עובד עם מסדי נתונים רציונליים ושפת השאילתות המובנית (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 על Ubuntu 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)
כפי שהפלט מציין, שבעה עשר ימים אחרי 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
, ותצמצם את התוצאות שלך באמצעות ה-Clause 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)
בחלק זה, ביצעת חישובים חשבוניים על תאריכים ושעות עם ההצהרה SELECT
ולצורך מעשי על הנתונים הדוגמא. למחרת, תתאמן בשאילתות באמצעות פונקציות שונות לתאריכים ושעות.
שימוש בפונקציות לתאריך ולשעה וביטויי טווח
ישנן מספר פונקציות שניתן להשתמש בהן כדי למצוא ולשלוט בערכי תאריך ושעה ב- 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
לדוגמה, כדי למצוא את התאריך חמישה ימים מהיום, תוכל להריץ את השאילתא הבאה:
הדוגמה הזו מוצאת את ערך התאריך הנוכחי, ואז מוסיפה לו את ביטוי המרווח INTERVAL '5' DAY
. זה מחזיר את התאריך 5 ימים מהיום:
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)
הפלט מציג את זמן הריצה הקצר ביותר של כל אחד מהרצים, במקרה זה מינימום של שישה דקות ושלושים שניות עבור בולט, ושבע דקות וחמישה שניות עבור פליקס.
לבסוף, מצא את זמן הריצה הארוך ביותר של כל אחד מהרצים. תוכל להשתמש בתחביר זהה לשאילתה הקודמת, אך הפעם החלף את MIN
ב־MAX
:
Output+-------------+----------+
| runner_name | max_time |
+-------------+----------+
| bolt | 03:23:10 |
| felix | 04:02:10 |
+-------------+----------+
2 rows in set (0.00 sec)
הפלט מציין כי זמן הריצה הארוך ביותר של בולט היה סך הכול של שלוש שעות, 23 דקות, ועשר שניות; ושל פליקס היה סך הכול של ארבע שעות, שתי דקות, ועשר שניות.
עכשיו נשאל על מידע ברמה גבוהה על כמות השעות הכוללת שבהן כל רץ ביצע ריצה. לצורך פנייה זו, נשתמש בפונקציית האיגרגציה SUM
כדי למצוא את סכום הכולל של השעות על פי הנוסחה זמן_סיום - זמן_התחלה
, ונשתמש ב־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 פורשת את הערכים כזמן ומחשבת אותם כך, כך שתוצאות של פליקס נפרקות לסך כולל של עשר שעות, דקה אחת ו־44 שניות; ושל בולט לשש שעות, תשע דקות ו־20 שניות. זהו דוגמה לכיצד מספר מימושים שונים של מסדי נתונים עשויים לפרש ערכי נתונים בדרכים שונות גם אם הם משתמשים באותה שאילתה וסט נתונים.
מסקנה
הבנת כיצד להשתמש בתאריך ובזמן ב־SQL שימושי כאשר מתבצעת שאילתה עבור תוצאות מסוימות כמו דקות, שניות, שעות, ימים, חודשים, שנים; או קומבינציה של כל אלו. בנוסף, קיימות רבות פונקציות זמן ותאריך הזמינות המקלות על מציאת ערכים מסוימים, כמו התאריך או השעה הנוכחית. בעוד שהמדריך הזה השתמש רק בחשבון חיבור וחיסור על תאריכים וזמנים ב־SQL, ניתן להשתמש בערכי תאריך וזמן עם כל ביטוי מתמטי. למד עוד מהמדריך שלנו על ביטויים מתמטיים ופונקציות כוללות ונסה אותם בשאילתות שלך של תאריך וזמן.
Source:
https://www.digitalocean.com/community/tutorials/how-to-work-with-dates-and-times-in-sql