בחינת המשפט SELECT
Transact-SQL או T-SQL, הוא חייג של שפת ה- SQL הסטנדרטית ANSI המשמשת את המוצרים והשירותים של Microsoft SQL. הוא דומה ל- SQL רגיל. רוב המוקד שלנו יהיה במשפט SELECT, הכולל את האפשרויות והריאציות הרבות ביותר של כל משפט DML.
נתחיל בהסתכלות ברמה גבוהה על אופן העיבוד של משפט SELECT. הסדר שבו נכתב משפט SELECT אינו הסדר שבו הוא מוערך ומעובד על-ידי מנגנון מסד הנתונים של SQL Server.
שקול את השאילתה הבאה:
SELECT OrderDate, COUNT(OrderID) AS Orders
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
ORDER BY OrderDate DESC;
השאילתה כוללת משפט SELECT, המורכב ממשתתפים מרובים, שכל אחד מהם מגדיר פעולה ספציפית שיש להחיל על הנתונים המאוחזרים. לפני שנבחן את סדר זמן הריצה של פעולות, נבחן בקצרה את הפעולות שהשאילתה עושה, למרות שפרטי הפסוקיות השונות לא ייכללו במודול זה.
המשפט SELECT מחזיר את העמודה OrderDate ואת ספירת ערכי OrderID, שאליהם מקצה את ההזמנות של השם (או הכינוי):
SELECT OrderDate, COUNT(OrderID) AS Orders
פסוקית FROM מזהה איזו טבלה היא מקור השורות עבור השאילתה; במקרה זה, זוהי הטבלה Sales.SalesOrder :
FROM Sales.SalesOrder
משפט WHERE מסנן שורות מחוץ לתוצאות, ושומרת רק את השורות הממלאות את התנאי שצוין; במקרה זה, הזמנות עם מצב "נשלח":
WHERE Status = 'Shipped'
המשפט GROUP BY לוקח את השורות התואמות את תנאי המסנן ומקבבץ אותן לפי OrderDate, כך שכל השורות עם אותה OrderDate נחשבות לקבוצה בודדת ושורה אחת מוחזרת עבור כל קבוצה:
GROUP BY OrderDate
לאחר יצירת הקבוצות, משפט HAVING מסנן את הקבוצות בהתבסס על סינדיקאט משלה. רק תאריכים עם יותר מההזמנות ייכללו בתוצאות:
HAVING COUNT(OrderID) > 1
למטרות תצוגה מקדימה של שאילתה זו, המשפט הסופי הוא ORDER BY, אשר ממיין את הפלט בסדר יורד של OrderDate:
ORDER BY OrderDate DESC;
כעת, לאחר שראית מה כל פסוקית עושה, נבחן את הסדר שבו SQL Server מעריך אותן בפועל:
- פסוקית FROM מוערכת תחילה, כדי לספק את שורות המקור עבור שאר המשפט. טבלה וירטואלית נוצרת ועברת לשלב הבא.
- משפט WHERE הבא להערכה, סינון שורות אלה מטבלת המקור התואמות לפידיקאט. הטבלה הווירטואלית המסוננים מועברת לשלב הבא.
- GROUP BY הוא הבא, ארגון השורות בטבלה הווירטואלית בהתאם לערכים ייחודיים שנמצאו ברשימה GROUP BY. טבלה וירטואלית חדשה נוצרת, המכילה את רשימת הקבוצות, והיא מועברת לשלב הבא. מנקודה זו בזרימת הפעולות, רכיבים אחרים עשויים להפנות רק לעמודות ברשימה GROUP BY או בפונקציות צבירה.
- פסוקית HAVING מוערכת בשלב הבא, וסינון קבוצות שלמות בהתבסס על החזרה שלו. הטבלה הווירטואלית שנוצרה בשלב 3 מסוננים ועברים לשלב הבא.
- משפט SELECT יופעל לבסוף, וקבע אילו עמודות יופיעו בתוצאות השאילתה. מאחר שפסוקית SELECT מוערכת לאחר השלבים האחרים, לא ניתן להשתמש בכינויי עמודה (בדוגמה שלנו, Orders) שנוצרו שם במשפט GROUP BY או HAVING.
- המשפט ORDER BY הוא האחרון לביצוע, תוך מיון השורות כפי שנקבע על-ידי רשימת העמודות שלו.
כדי להחיל הבנה זו על השאילתה לדוגמה שלנו, הנה הסדר הלוגי בזמן הריצה של משפט SELECT לעיל:
FROM Sales.SalesOrder
WHERE Status = 'Shipped'
GROUP BY OrderDate
HAVING COUNT(OrderID) > 1
SELECT OrderDate, COUNT(OrderID) AS Orders
ORDER BY OrderDate DESC;
לא כל המשפטים האפשריים נדרשים בכל משפט SELECT שאתה כותב. המשפט הנדרש היחיד הוא משפט SELECT, שניתן להשתמש בו בעצמו במקרים מסוימים. בדרך כלל פסוקית FROM נכללת גם כדי לזהות את הטבלה הנמצאת בשאילתה. בנוסף, Transact-SQL פסוקיות אחרות שניתן להוסיף.
כפי שראית, אינך כותב שאילתות T-SQL באותו סדר שבו הן מוערכים באופן לוגי. סדר זמן הריצה של ההערכה קובע אילו נתונים יהיו זמינים לאילו משפטים, מאחר שלפסוקית יש גישה למידע שכבר זמין בפסוקית שכבר מעובדת. מסיבה זו, חשוב להבין את סדר העיבוד הלוגי האמיתי בעת כתיבת שאילתות.
בחירת כל העמודות
פסוקית SELECT נקראת לעתים קרובות רשימת SELECT, מאחר שהיא מפרטת את הערכים שיש להחזיר בתוצאות השאילתה.
הדרך הפשוטה ביותר של משפט SELECT היא השימוש בתו הכוכבית (*) כדי להחזיר את כל העמודות. כאשר משתמשים בו בשאילתות T-SQL, הוא נקרא כוכב. למרות ש- SELECT * מתאים לבדיקה מהירה, עליך להימנע משימוש בו למטרות ייצור מהסיבות הבאות:
- שינויים בטבלה שתוסיף או תסדר מחדש עמודות ישתקפו בתוצאות השאילתה, דבר שעשוי לגרום לפלט בלתי צפוי עבור יישומים או דוחות המשתמשים בשאילתה.
- החזרת נתונים שאינם דרושים עשויה להאט את השאילתות שלך גורמת לבעיות ביצועים אם טבלת המקור מכילה מספר רב של שורות.
לדוגמה, הדוגמה הבאה מאחזרת את כל העמודות מהטבלה Production.Product (היפותטית ).
SELECT * FROM Production.Product;
התוצאה מהשאילתה היא ערכת שורות המכילה את כל העמודות עבור כל השורות בטבלה, שעשויה להיראות בערך כך:
מזהה מוצר
שם
ProductNum
צבע
קו רוחב רגיל
מחיר רשימה
גודל
משקל
מזהה מוצר
680
מסגרת כביש HL - שחור, 58
FR-R92B-58
שחור
1059.31
1431.5
58
1016.04
18
706
מסגרת כביש HL - אדום, 58
FR-R92R-58
אדום
1059.31
1431.5
58
1016.04
18
707
ספורט-100 קסדה, אדום
HL-U509-R
אדום
13.0863
34.99
35
708
ספורט-100 קסדה, שחור
HL-U509
שחור
13.0863
34.99
35
...
...
...
...
...
...
...
...
...
בחירת עמודות ספציפיות
רשימת עמודות מפורשת מאפשרת לך לשלוט באופן מדויק בעמודות המוחזרות וב באיזה סדר. כל עמודה בתוצאה תכלול את שם העמודה ככותרת העליונה.
לדוגמה, שקול את השאילתה הבאה; שמשתמשת שוב בטבלה ההיפותטית Production.Product .
SELECT ProductID, Name, ListPrice, StandardCost
FROM Production.Product;
הפעם, התוצאות כוללות רק את העמודות שצוינו:
מזהה מוצר
שם
מחיר רשימה
קו רוחב רגיל
680
מסגרת כביש HL - שחור, 58
1431.5
1059.31
706
מסגרת כביש HL - אדום, 58
1431.5
1059.31
707
ספורט-100 קסדה, אדום
34.99
13.0863
708
ספורט-100 קסדה, שחור
34.99
13.0863
...
...
...
...
בחירת ביטויים
בנוסף לאחזור עמודות המאוחסנות בטבלה שצוינה, משפט SELECT יכול לבצע חישובים ומניפולציות, המשתמשים באופרטורים כדי לשלב עמודות וערכים או עמודות מרובות. תוצאת החישוב או המניפולציה חייבת להיות תוצאה של ערך יחיד (סקארי) שתופיע בתוצאה כעמודה נפרדת.
לדוגמה, השאילתה הבאה כוללת שני ביטויים:
SELECT ProductID,
Name + '(' + ProductNumber + ')',
ListPrice - StandardCost
FROM Production.Product;
התוצאות מהשאילתה עשויות להיראות כך:
מזהה מוצר
680
מסגרת כביש HL - שחור, 58(FR-R92B-58)
372.19
706
מסגרת כביש HL - אדום, 58(FR-R92R-58)
372.19
707
קסדת ספורט-100 אדומה (HL-U509-R)
21.9037
708
ספורט-100 קסדה, שחור(HL-U509)
21.9037
...
...
...
יש כמה דברים מעניינים שיש לשים לב לגבי תוצאות אלה:
- לעמודות המוחזרות על-ידי שני הביטויים אין שמות עמודות. בהתאם לכלי שבו אתה משתמש לשליחת השאילתה שלך, ייתכן שתרצה לציין שם עמודה חסר על-ידי כותרת עמודה ריקה, מחוון ליטרל "ללא שם עמודה" או שם ברירת מחדל כגון column1. נראה כיצד לציין כינוי עבור שם העמודה בשאילתה בהמשך סעיף זה.
- הביטוי הראשון משתמש באופרטור + כדי לשרשר ערכי מחרוזת (מבוססת תווים), - בעוד שהביטוי השני משתמש באופרטור כדי לחסר ערך מספרי אחד מהערך המספרי השני. בעת שימוש עם ערכים מספריים, האופרטור + מבצע חיבור. באופן ברור, חשוב להבין את סוגי הנתונים של העמודות שאתה כולל בביטויים. נדון בסוגי נתונים בסעיף הבא.
ציון כינויי עמודות
באפשרותך לציין כינוי עבור כל עמודה המוחזרת על-ידי שאילתת SELECT, לחלופין לשם עמודת המקור או כדי להקצות שם לפלט של ביטוי.
לדוגמה, להלן אותה שאילתה כמו בעבר, אך עם כינויים שצוינו עבור כל אחת מהעמודות:
SELECT ProductID AS ID,
Name + '(' + ProductNumber + ')' AS ProductName,
ListPrice - StandardCost AS Markup
FROM Production.Product;
התוצאות מהשאילתה כוללים את שמות העמודות שצוינו:
מזהה
שם מוצר
סימון
680
מסגרת כביש HL - שחור, 58(FR-R92B-58)
372.19
706
מסגרת כביש HL - אדום, 58(FR-R92R-58)
372.19
707
קסדת ספורט-100 אדומה (HL-U509-R)
21.9037
708
ספורט-100 קסדה, שחור(HL-U509)
21.9037
...
...
...
הערה
מילת המפתח AS היא אופציונלית בעת ציון כינוי, אך מומלץ לכלול אותה לה הבהרה.
שאילתות עיצוב
תוכל לתשומת לבך, מהדוגמאות בסעיף זה, תוכל להיות גמיש לגבי האופן שבו אתה מעצב את קוד השאילתה. לדוגמה, באפשרותך לכתוב כל פסוקית (או את השאילתה כולה) בשורה בודדת, או לנתק אותה על-פני שורות מרובות. ברוב מערכות מסדי הנתונים, הקוד אינו תלוי רישיות, ורכיבים מסוימים של שפת T-SQL הם אופציונליים (כולל מילת המפתח AS כפי שהוזכר קודם לכן, ואפילו נקודה-פסיק בסוף משפט).
שקול את הקווים המנחים הבאים כדי להפוך את קוד ה- T-SQL שלך לקריא יותר (ולכן קל יותר להבין ולאתר באגים!):
- הפוך מילות מפתח של T-SQL לרישיות, כגון SELECT, FROM, AS וכן הלאה. הפיכת מילות מפתח לרישיות היא מוסכמה נפוצה שמקלה עליך למצוא כל פסוקית במשפט מורכב.
- התחל שורה חדשה עבור כל פסוקית ראשית במשפט.
- אם הרשימה SELECT מכילה יותר מכמה עמודות, ביטויים או כינויים, שקול להוסיף רשימה של כל עמודה בשורה משלה.
- הסט פנימה שורות המכילות מחלקת משנה או עמודות כדי להבהיר איזה קוד שייך לכל משפט ראשי.