מדריך T-SQL: לולאות


הדוגמאות בפוסט הזה מתייחסות לבסיס נתונים המבוסס על הסדרה הפופולרית "משחקי הכס" שיצרתי במיוחד עבור המדריך הזה. אם אתם רוצים להוריד אותו בעצמכם או סתם להבין מה זה בכלל אתם יכולים ללחוץ כאן

במקרים רבים נרצה לחזור על פעולה מסוימת כמו למשל לבצע בדיקה מול נתון מסוים בכל שורה בטבלה. אם ננסה לכתוב את הבדיקה מספר רב של פעמים זה יהיה מתיש, לא יעיל, לא קריא וגם לא יאפשר לנו גמישות בכתיבת הקוד – מה אם אנחנו לא יודעים כמה שורות יש? מה אם מחר יוסיפו שורה חדשה ונרצה שהתכנית תכלול גם בדיקה עליה?

לכן במקרים כאלה נשתמש בלולאות.


לולאות WHILE

ב- T-SQL אנחנו יכולים ליצור לולאות אשר ירוצו (יבצעו את אותן פעולות שוב ושוב) כל עוד תנאי מסוים מתקיים. התנאי הזה נקרא "תנאי כניסה" מפני שהוא מגדיר תנאי שאם מתקיים, תכנס התכנית לתוך הלולאה ותתחיל לבצע את הקוד שבתוכה. יש להגדיר את התנאי בתחילת הלולאה, מייד אחרי המילה WHILE וזאת הסיבה שהלולאות נקראות "לולאות WHILE". זהו הסוג היחיד של לולאות ב-T-SQL למרות שבשפות תכנות אחרות יש סוגים נוספים של לולאות.


מבנה לולאת WHILE

המבנה הבסיסי של לולאה נראה כך:

התנאי יתבסס על ביצוע השוואה כלשהי בין ערכים, כאשר בדרך כלל לפחות אחד מהם הוא משתנה. יש להקפיד כמובן שהתנאי יפסיק להתקיים בשלב מסוים כדי שהתכנית לא תתקע בלולאה אינסופית.


יצירת לולאה בסיסית

הנה דוגמה ללולאה אשר מדפיסה את כל המספרים מ-1 עד 10:

בשורה 1 אנו מגדירים משתנה בשם counter שבעזרתו נוכל לפקח על התקדמות הלולאה ועל מספר הפעמים שתתבצע. המשתנה מאותחל למספר 1 (שורה 3) והלולאה אמורה לרוץ כל עוד הוא קטן מ-11. בגלל שהתנאי הזה כרגע נכון (המספר 1 אכן קטן מ-11), התכנית נכנסת ללולאה ומתחילה לבצע אותה שוב ושוב. הלולאה מבצעת בסך הכל שתי פעולות: היא מדפיסה את המשתנה counter (שכרגע שווה ל-1) ומאתחלת את המשתנה לעצמו ועוד 1, כלומר מגדילה את ערכו ב-1. הפעולה הזאת קריטית מפני שבלעדיה counter תמיד יהיה שווה ל-1 מה שאומר שהתנאי שהוגדר בתחילת הלולאה לעולם לא יחדל להתקיים וכך נתקע בלולאה אינסופית.

הדפסת המשתנה עצמו עוזרת לנו לעקוב אחר התקדמות הלולאה כאשר בכל ריצה counter מחזיק ערך גדול ב-1 ממה שהחזיק בריצה הקודמת של הלולאה. לאחר 10 ריצות כאלה counter כבר שווה ל-11 וכאשר SQL Server בודק שוב את התנאי בתחילת הלולאה (על counter להיות קטן מ-11) הוא מגלה כי התנאי כבר לא מתקיים ולכן יוצא מהלולאה ומסיים את התכנית. חשוב לזכור ש- SQL Server בודק בכל ריצה מחדש האם התנאי אכן מתקיים ורק אז מחליט אם להיכנס ללולאה או לא. במידה ונגדיר לולאה שתנאי הכניסה שלה לא מתקיים מלכתחילה, SQL Server ידלג עליה לגמרי מבלי לבצע אפילו ריצה אחת של הלולאה ופשוט ימשיך הלאה להמשך התכנית.


שימוש ב-SELECT בתוך לולאה

בואו נבחן דוגמה מעט מורכבת יותר. נניח שאני רוצה להציג רשימה של כל הבתים (או קבוצות אחרות) ומספר הנאמנים לכל קבוצה מטבלת Factions. אפשר להציג את המידע הזה באמצעות שאילתה פשוטה, אבל אם רוצים להדפיס את המידע ללשונית ה-messages כדאי להשתמש בלולאה. בשלב הראשון נגדיר משתנה שיתפקד כמונה (בעזרתו נגביל את מספר הריצות שהלולאה תבצע), משתנה שיכיל את מספר הדמויות הנאמנות לכל בית, ואת שם הבית שאותו נבדוק בכל ריצה:


עכשיו נתחיל את התוכנית עצמה שבעצם תכיל רק לולאה. בתנאי הכניסה של הלולאה נרצה לוודא שהמונה לא גדול ממספר הבתים המקסימלי בטבלה. אני יכול לבדוק את טבלת Factions ולראות כמה קבוצות יש שם כרגע אבל המספר הזה לא בהכרח יהיה נכון בעתיד ולכן אני רוצה לבצע את הבדיקה בצורה דינמית בכל פעם שהתכנית הזאת תתבצע. לכן אכניס את השאילתה שבודקת את המספר לתוך תנאי הבדיקה עצמו:


זה יעבוד כמובן, אבל הבעיה היא ש-SQL Server יחשב מחדש את הערך הזה בכל ריצה וריצה של הלולאה עצמה. זה קצת *יותר מדי* דינמי לטעמי ולא יעיל מבחינת ביצועים. כדי לייעל את השורה הזאת אני אוסיף לרשימת המשתנים בראש התכנית משתנה אשר יכיל את הערך הזה ואבצע את ההשוואה מולו. כך בעצם אני לא מאלץ את המערכת לחשב את אותו ערך שוב ושוב ללא צורך.



בתוך הלולאה עצמה נשתמש במספר שמכיל המונה כדי לבחור כל פעם קבוצה שונה ולהכניס בכל ריצה נתונים מבית שונה לתוך המשתנים הרלוונטיים – שם הקבוצה לתוך factionName ומספר הדמויות הנאמנות לקבוצה הספציפית הזאת לתוך characterNum:

בשלב הבא נדפיס את הנתונים עבוד כל קבוצה (זאת בעצם כל הפואנטה של התכנית הזאת)


בשלב האחרון נדאג לקדם את המונה כדי שבריצה הבאה הבדיקה תתבצע על הקבוצה הבאה (וגם למנוע ריצה אינסופית של הלולאה)

את פעולת הקידום של המשתנה ניתן גם לכתוב בצורה מקוצרת, ככה:


הכוונה בביטוי הזה הוא בעצם הצב במשתנה את עצמו + המספר 1.

זהו, התכנית הסופית נראית ככה:









© כל הזכויות שמורות לאלעד פלג הדרכות 2020