בגרות במדעי המחשב תכנות באינטרנט 899372 - קיץ 2026
נבחנים אקסטרניים · שאלון 899372 · 9 שאלות · 2 שעות · פתרון מלא לכל סעיף
בחינת הבגרות במדעי המחשב, תכנות באינטרנט, קיץ 2026, כל 9 השאלות כמו בשאלון. לכל סעיף יש תשובה ופתרון מלא: הרעיון, הקוד או המעקב, ובדיקה קצרה. כל קוד מופיע ב-Java וב-C#. נסו לפתור לבד, ואז פתחו את הפתרון.
הוראות הבחינה (כמו בשאלון)
א. משך הבחינה: שעתיים.
ב. מבנה השאלון ומפתח הערכה:
| פרק | נקודות | |
|---|---|---|
| פרק ראשון | (10*3) | 30 נקודות |
| פרק שני | (20*2) + (10*1) | 50 נקודות |
| פרק שלישי | (20*1) | 20 נקודות |
| סך הכול | 100 נקודות |
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
יש לכתוב במחברת הבחינה בלבד. יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
הערה: לפי הודעת משרד החינוך "ההנחיות החדשות למענה על שאלות הבחינה" (מדעי המחשב, 899372, קיץ תשפ"ו 2026), מבנה השאלון ומפתח ההערכה שונו: בפרק ראשון יש לענות על 2 שאלות מתוך 3 שאלות, לכל שאלה – 10 נקודות, סך הכול לפרק: 20 נקודות. בפרקים שני ושלישי יש לענות על 4 שאלות מתוך שני הפרקים, לכל שאלה – 20 נקודות, סך הכול: 80 נקודות. (השאלון עצמו מדפיס את המבנה הרגיל, ולכן גם הניקוד המודפס ליד השאלות הוא הניקוד הרגיל.)
פרק ראשון
ענו על שלוש השאלות 3-1 (לכל שאלה – 10 נקודות).
שאלה 1 · תפקיד האובייקט Request
מהו תפקידו של אובייקט Request בתקשורת בין לקוח לשרת?
א. לשלוח תגובה מהשרת לדפדפן (ללקוח)
ב. להכיל את הבקשה שנשלחה מהדפדפן (מהלקוח) לשרת
ג. לשמור מידע במסד הנתונים
ד. לאמת את זהות המשתמש
מהו תפקידו של אובייקט Request בתקשורת בין לקוח לשרת?
◂ פתרון מלא לשאלה 1
פתרון
ב. להכיל את הבקשה שנשלחה מהדפדפן (מהלקוח) לשרת
מה נדרש – לבחור את התיאור הנכון של האובייקט Request.
רעיון – בתקשורת לקוח-שרת הדפדפן (הלקוח) שולח בקשה (Request) לשרת, והשרת מחזיר תגובה (Response). ב-ASP.NET האובייקט Request מייצג את הבקשה שהגיעה מהלקוח: דרכו השרת קורא את הנתונים שנשלחו, למשל Request.Form["userCode"] (שדות טופס שנשלחו ב-POST) או Request.QueryString["id"] (פרמטרים בכתובת).
פתרון – התשובה הנכונה: ב.
בדיקה – למה האחרות שגויות:
Response (למשל Response.Write, Response.Redirect).SqlConnection, SqlCommand וכו'), לא בעזרת Request.טעות נפוצה: לבלבל בין Request (מהלקוח לשרת) לבין Response (מהשרת ללקוח).
שאלה 2 · שאילתת SQL – שירי Pop משנת 2020
במסד נתונים של אפליקציית מוזיקה מוגדרת טבלה בשם Songs ובה נתוני שירים. בטבלה העמודות הבאות:
כתבו שאילתה בשפת SQL המחזירה את שמות השירים שהושמעו יותר מ־1000 פעמים ושייכים לסוג המוזיקה Pop ויצאו בשנת 2020.
כתבו שאילתה בשפת SQL המחזירה את שמות השירים שהושמעו יותר מ־1000 פעמים ושייכים לסוג המוזיקה Pop ויצאו בשנת 2020.
◂ פתרון מלא לשאלה 2
פתרון
SELECT songName FROM Songs WHERE plays > 1000 AND type = 'Pop' AND releaseYear = 2020;
מה נדרש – להחזיר עמודה אחת (songName) של השירים שמקיימים שלושה תנאים יחד.
רעיון – בוחרים רק את העמודה songName מהטבלה Songs, ומסננים ב-WHERE עם שלושה תנאים שמחוברים ב-AND (כי כל התנאים צריכים להתקיים יחד):
plays > 1000 – "יותר מ־1000" פירושו גדול ממש (1000 עצמו לא נכלל).type = 'Pop' – ערך טקסט נכתב בין גרשיים בודדים.releaseYear = 2020 – מספר נכתב בלי גרשיים.פתרון
SELECT songName
FROM Songs
WHERE plays > 1000 AND type = 'Pop' AND releaseYear = 2020;בדיקה – השאילתה על טבלה קטנה לדוגמה:
| songName | plays | type | releaseYear | נבחר? |
|---|---|---|---|---|
| Blinding Lights | 5000 | Pop | 2020 | כן |
| Levitating | 1000 | Pop | 2020 | לא (1000 אינו יותר מ־1000) |
| Watermelon Sugar | 2500 | Pop | 2019 | לא (שנה אחרת) |
| Savage | 3000 | HipHop | 2020 | לא (סוג אחר) |
| Dynamite | 1001 | Pop | 2020 | כן |
התוצאה: Blinding Lights, Dynamite.
טעות נפוצה: לכתוב plays >= 1000 (כולל 1000), או לחבר את התנאים ב-OR במקום AND.
שאלה 3 · פלט של פעולת שרת – טבלת HTML
לפניכם פעולה בשם Func הכתובה בצד שרת. העתיקו למחברתכם את מה שיוצג בדפדפן לאחר הרצת הפעולה Func עם הפרמטר num = 6.
public void Func (int num) {
string str = "<table border = '1'>";
for (int i = 1; i <= num; i++)
{
if (i % 6 == 0)
str += "<tr><td>Fizz</td></tr>";
else if (i % 3 == 0)
str += "<tr><td>Buzz</td></tr>";
else
str += "<tr><td>" + i + "</td></tr>";
}
str += "</table>";
Response.Write (str);
}העתיקו למחברתכם את מה שיוצג בדפדפן לאחר הרצת הפעולה Func עם הפרמטר num = 6.
◂ פתרון מלא לשאלה 3
פתרון
טבלה עם מסגרת, עמודה אחת ו־6 שורות, מלמעלה למטה: 1, 2, Buzz, 4, 5, Fizz
מה נדרש – לא את קוד ה-HTML, אלא את מה שהדפדפן מציג אחרי שהשרת שולח לו את המחרוזת str.
רעיון – הפעולה בונה מחרוזת HTML של טבלה (border = '1' – טבלה עם מסגרת). בכל סיבוב של הלולאה (i מ־1 עד 6) נוספת שורה (<tr>) ובה תא אחד (<td>). לכן מתקבלת טבלה בעלת עמודה אחת ו־6 שורות. התוכן של כל תא נקבע לפי התנאים, ושימו לב שהבדיקה i % 6 == 0 נעשית לפני i % 3 == 0.
פתרון – מעקב:
| i | i % 6 == 0 ? | i % 3 == 0 ? | התוכן שנוסף |
|---|---|---|---|
| 1 | לא | לא | <tr><td>1</td></tr> |
| 2 | לא | לא | <tr><td>2</td></tr> |
| 3 | לא | כן | <tr><td>Buzz</td></tr> |
| 4 | לא | לא | <tr><td>4</td></tr> |
| 5 | לא | לא | <tr><td>5</td></tr> |
| 6 | כן | (לא נבדק) | <tr><td>Fizz</td></tr> |
המחרוזת שנשלחת לדפדפן:
<table border = '1'><tr><td>1</td></tr><tr><td>2</td></tr><tr><td>Buzz</td></tr><tr><td>4</td></tr><tr><td>5</td></tr><tr><td>Fizz</td></tr></table>מה יוצג בדפדפן – טבלה עם מסגרת סביב כל תא, עמודה אחת ושש שורות:
| 1 |
| 2 |
| Buzz |
| 4 |
| 5 |
| Fizz |
בדיקה – עבור num = 6 מתקבלת בדיוק המחרוזת שלמעלה; התאים לפי הסדר: 1, 2, Buzz, 4, 5, Fizz.
טעות נפוצה: לכתוב Buzz עבור 6 (כי 6 מתחלק גם ב־3) – אבל התנאי הראשון i % 6 == 0 מתקיים ולכן נכתב Fizz וה-else if לא נבדק. טעות נוספת: לצייר את התאים בשורה אחת – כל תא נמצא ב-<tr> משלו, ולכן הם מוצגים זה מתחת לזה.
פרק שני
ענו על שלוש שאלות:
שאלה 4 (שאלת חובה – 10 נקודות) ועל שתיים מן השאלות 7-5 (לכל שאלה - 20 נקודות)
שאלה 4 · JavaScript – בדיקת הצפנת קוד משתמש (השלמת קוד)
באתר להזמנת כרטיסים יש שדה להזנת קוד משתמש:
<input type="text" maxlength="10" name="userCode" id="userCode" />כדי להגן על המשתמשים, המערכת עושה שימוש בשיטת הצפנה. מחרוזת הקוד המקורית (originalCode) מומרת למחרוזת מוצפנת (encryptedCode) באופן הבא:
תווי הקוד המקורי משובצים בתוך המחרוזת המוצפנת כך שכל תו מהמחרוזת המקורית מופיע במרווח קבוע של X תווים במחרוזת המוצפנת. כלומר, התו הראשון של הקוד המקורי ממוקם במקום 0 במחרוזת המוצפנת, התו השני במקום ה- X במחרוזת המוצפנת, וכן הלאה – כל X תווים – עד להשלמת כל תווי המחרוזת המקורית (התו האחרון במחרוזת המקורית הוא גם התו האחרון במחרוזת המוצפנת).
בהתאם לכך, אם נבחר את התווים במיקומים 0, X, 2X, 3X וכן הלאה מתוך encryptedCode נקבל בחזרה את originalCode
דוגמה:
originalCode = "ACE"
encryptedCode = "ATCDE"
X = 2
דוגמה נוספת:
originalCode = "ACE"
encryptedCode = "AVBCDDE"
X = 3
הפעולה שלפניכם בודקת האם ההצפנה תקינה. בפעולה חסרים שישה ביטויים המסומנים במספרים (1)–(6).
כתבו במחברת הבחינה את המספרים (1)–(6) ואת הביטויים החסרים שכל מספר מייצג.
<script>
function isValidCode (var originalCode, var encryptedCode, var X)
{
var i = 0;
var j = 0;
// נסרוק את שתי המחרוזות כל עוד לא הגענו לסוף שלהן
while (_________(1)______ && _______(2)_________)
{
// אם התווים במיקומים המתאימים אינם שווים – הקוד אינו תקין
if (______(3)______)
return false;
// נתקדם בשתי המחרוזות
____(4)________; // i
_____(5)_______; // j
}
// אם לא סיימנו לעבור עד סוף שתי המחרוזות – הקוד אינו תקין
if (______(6)______)
return false;
return true;
}
</script>כתבו במחברת הבחינה את המספרים (1)–(6) ואת הביטויים החסרים שכל מספר מייצג.
◂ פתרון מלא לשאלה 4
פתרון
(1) i < originalCode.length
(2) j < encryptedCode.length
(3) originalCode.charAt(i) != encryptedCode.charAt(j)
(4) i++
(5) j = j + X
(6) i < originalCode.length || j < encryptedCode.length
מה נדרש – להשלים שישה ביטויים בפעולה שבודקת אם encryptedCode הוא הצפנה תקינה של originalCode במרווח X.
רעיון – משתמשים בשני אינדקסים:
i עובר על originalCode תו אחרי תו (0, 1, 2, ...);j עובר על encryptedCode בקפיצות של X (0, X, 2X, ...).בכל צעד משווים את התו ה-i במקור לתו ה-j במוצפן. אם יש אי-התאמה – ההצפנה אינה תקינה. בסוף, כלשון ההערה בקוד, בודקים שסיימנו לעבור עד סוף שתי המחרוזות: אם נשאר אינדקס שעדיין קטן מאורך המחרוזת שלו – הקוד אינו תקין.
פתרון
| מספר | ביטוי | הסבר |
|---|---|---|
| (1) | i < originalCode.length | לא הגענו לסוף המחרוזת המקורית |
| (2) | j < encryptedCode.length | לא חרגנו מסוף המחרוזת המוצפנת |
| (3) | originalCode.charAt(i) != encryptedCode.charAt(j) | התווים במיקומים המתאימים שונים |
| (4) | i++ | מתקדמים תו אחד במקור |
| (5) | j = j + X | מתקדמים X תווים במוצפן |
| (6) | i < originalCode.length || j < encryptedCode.length | לא הגענו לסוף אחת המחרוזות (נשארו בה תווים) |
הפעולה המלאה:
function isValidCode(originalCode, encryptedCode, X)
{
var i = 0;
var j = 0;
// נסרוק את שתי המחרוזות כל עוד לא הגענו לסוף שלהן
while (i < originalCode.length && j < encryptedCode.length)
{
// אם התווים במיקומים המתאימים אינם שווים – הקוד אינו תקין
if (originalCode.charAt(i) != encryptedCode.charAt(j))
return false;
// נתקדם בשתי המחרוזות
i++; // i
j = j + X; // j
}
// אם לא סיימנו לעבור עד סוף שתי המחרוזות – הקוד אינו תקין
if (i < originalCode.length || j < encryptedCode.length)
return false;
return true;
}הערה על כותרת הפעולה: בשאלון כתוב function isValidCode (var originalCode, var encryptedCode, var X). ב-JavaScript לא כותבים var ברשימת הפרמטרים (זו שגיאת תחביר), ולכן בפתרון הכותרת היא function isValidCode(originalCode, encryptedCode, X). אין לכך השפעה על הביטויים החסרים.
בדיקה
מעקב עבור הדוגמה הראשונה (originalCode = "ACE", encryptedCode = "ATCDE", X = 2, אורכים 3 ו־5):
| i | j | originalCode.charAt(i) | encryptedCode.charAt(j) | שווים? |
|---|---|---|---|---|
| 0 | 0 | A | A | כן |
| 1 | 2 | C | C | כן |
| 2 | 4 | E | E | כן |
| 3 | 6 | – | – | הלולאה נעצרת (3 < 3 שקר) |
בסוף: i < 3 שקר, j < 5 (6 < 5) שקר ⇐ התנאי (6) שקר ⇐ מוחזר true.
התוצאות:
isValidCode("ACE", "ATCDE", 2) → true; isValidCode("ACE", "AVBCDDE", 3) → true (שתי הדוגמאות מהשאלה).isValidCode("ACE", "ATCDF", 2) → false (התו האחרון שונה).isValidCode("ACE", "ATCD", 2) → false (המוצפנת קצרה מדי – i לא הגיע לסוף).isValidCode("AC", "ATCDE", 2) → false (j לא הגיע לסוף המוצפנת).הערה (דיוק): אחרי הלולאה j כבר קפץ X מקומות מעבר לתו האחרון שנבדק, ולכן הביטוי (6) לא מזהה 1 עד X−1 תווים מיותרים בסוף המוצפנת (למשל "ACE", "ATCDEF", 2 מחזיר true). בדיקה מדויקת לגמרי להגדרה היא i < originalCode.length || j - X != encryptedCode.length - 1; בבדיקה ממוחשבת של כל המחרוזות מעל {A,B} (מקור עד אורך 3, מוצפנת עד אורך 7, X מ־1 עד 4) הגרסה המדויקת נכונה תמיד, והגרסה שבתשובה שונה ממנה רק במקרים האלה.
טעות נפוצה: לקדם את j ב-1 במקום ב-X, או לבדוק בסעיף (3) שוויון (==) במקום אי-שוויון.
שאלה 5 · Session – הפניית משתמש בחדר כושר
באתר של חדר כושר, המשתמש בוחר תוכנית אימונים.
כדי לקבוע לאיזה דף יעבור המשתמש, האתר משתמש במשתני Session הבאים:
בהתבסס על משתנים אלה, האתר מפנה את המשתמש לדף המתאים:
כתבו בצד שרת קוד המתאים לדרישות.
כתבו בצד שרת קוד המתאים לדרישות.
◂ פתרון מלא לשאלה 5
פתרון
if (age >= 18 && isMember && visits >= 10) Response.Redirect("proWorkout.aspx");
else if (age >= 15 && (age < 18 || isMember)) Response.Redirect("basicWorkout.aspx");
else Response.Redirect("home.aspx");
מה נדרש – קוד C# בצד השרת שקורא את שלושת משתני ה-Session ומפנה (Redirect) לאחד משלושה דפים.
רעיון
int.Parse(Session["age"].ToString()), bool.Parse(Session["isMember"].ToString()) (אפשר גם המרה ישירה (int)Session["age"], (bool)Session["isMember"] אם נשמרו כ-int ו-bool).age >= 15 && (age < 18 || isMember).פתרון (בתוך Page_Load של הדף, או בתוך אירוע לחיצה על כפתור):
protected void Page_Load(object sender, EventArgs e)
{
int age = int.Parse(Session["age"].ToString());
bool isMember = bool.Parse(Session["isMember"].ToString());
int visits = int.Parse(Session["visits"].ToString());
if (age >= 18 && isMember && visits >= 10)
Response.Redirect("proWorkout.aspx");
else if (age >= 15 && (age < 18 || isMember))
Response.Redirect("basicWorkout.aspx");
else
Response.Redirect("home.aspx");
}בדיקה:
| age | isMember | visits | דף |
|---|---|---|---|
| 20 | true | 12 | proWorkout.aspx |
| 18 | true | 10 | proWorkout.aspx (גבולות כלולים) |
| 20 | true | 5 | basicWorkout.aspx (מנוי, אבל פחות מ־10 ביקורים) |
| 16 | false | 0 | basicWorkout.aspx (15–17 גם בלי מנוי) |
| 15 | false | 20 | basicWorkout.aspx |
| 20 | false | 30 | home.aspx (בגיר שאינו מנוי) |
| 14 | true | 30 | home.aspx (מתחת ל־15) |
בכל הצירופים של גיל 10–25, מנוי/לא מנוי וביקורים 0–15 המשתמש מופנה לדף הנכון.
טעות נפוצה: לכתוב age >= 15 && age < 18 || isMember בלי סוגריים. האופרטור && קודם ל-||, ולכן הביטוי מתפרש כ-(age >= 15 && age < 18) || isMember, ומנוי בן 12 יופנה בטעות ל-basicWorkout.aspx. טעות נוספת: להשוות את Session["age"] ישירות למספר בלי המרה.
protected void Page_Load(object sender, EventArgs e)
{
int age = int.Parse(Session["age"].ToString());
bool isMember = bool.Parse(Session["isMember"].ToString());
int visits = int.Parse(Session["visits"].ToString());
if (age >= 18 && isMember && visits >= 10)
Response.Redirect("proWorkout.aspx");
else if (age >= 15 && (age < 18 || isMember))
Response.Redirect("basicWorkout.aspx");
else
Response.Redirect("home.aspx");
}שאלה 6 · פעולת שרת IsFizzBuzz – סכום ספרות
נגדיר מספר FizzBuzz – מספר שלם חיובי שסכום הספרות שלו מתחלק ב-7 ללא שארית וגם המספר עצמו מתחלק ב-5 ללא שארית.
דוגמאות למספרים FizzBuzz:
דוגמאות למספרים שאינם FizzBuzz:
כתבו בצד שרת פעולה בשם IsFizzBuzz המקבלת מספר שלם חיובי – num, ומחזירה אמת אם המספר הוא FizzBuzz. אחרת, מחזירה שקר.
כתבו בצד שרת פעולה בשם IsFizzBuzz המקבלת מספר שלם חיובי – num, ומחזירה אמת אם המספר הוא FizzBuzz. אחרת, מחזירה שקר.
◂ פתרון מלא לשאלה 6
פתרון
אם num % 5 != 0 מחזירים false; אחרת מחשבים את סכום הספרות בלולאה (sum += n % 10; n /= 10) ומחזירים sum % 7 == 0.
מה נדרש – פעולה בוליאנית ב-C# (צד שרת) שבודקת שני תנאים: המספר מתחלק ב־5, וסכום ספרותיו מתחלק ב־7.
רעיון
num % 5 != 0 – אפשר להחזיר false מיד.n % 10 היא ספרת האחדות, ו-n / 10 (חלוקה בשלמים) "מוחקת" אותה. ממשיכים כל עוד n > 0. עובדים על עותק (n) כדי לא לשנות את num.sum % 7 == 0.פתרון
public bool IsFizzBuzz(int num)
{
if (num % 5 != 0)
return false;
int sum = 0;
int n = num;
while (n > 0)
{
sum += n % 10;
n = n / 10;
}
return sum % 7 == 0;
}בדיקה – מעקב עבור num = 455 (455 % 5 == 0, ממשיכים):
| n | n % 10 | sum |
|---|---|---|
| 455 | 5 | 5 |
| 45 | 5 | 10 |
| 4 | 4 | 14 |
| 0 | – | הלולאה נעצרת |
14 % 7 == 0 ⇐ מוחזר true.
התוצאות: 25 → True, 455 → True, 52 → False, 35 → False (כמו בשאלה); 70 → True, 5 → False, 160 → True. מספרי FizzBuzz עד 300: 25, 70, 95, 115, 160, 185, 205, 250, 275.
טעות נפוצה: לבדוק אם סכום הספרות מתחלק ב־5 (במקום המספר עצמו), או לחשב את סכום הספרות על num עצמו ואז לבדוק num % 5 אחרי הלולאה – כש-num כבר 0 (ו-0 מתחלק ב־5, כך שהבדיקה תמיד תצליח).
public bool IsFizzBuzz(int num)
{
if (num % 5 != 0)
return false;
int sum = 0;
int n = num;
while (n > 0)
{
sum += n % 10;
n = n / 10;
}
return sum % 7 == 0;
}שאלה 7 · SQL – טבלת SongsStats (3 מתוך 6 סעיפים)
במסד נתונים של אפליקציית מוזיקה יש טבלה ששמה SongsStats המכילה את נתוני השירים באפליקציה. העמודות בטבלה הן:
דוגמה לטבלה ובה שירים באפליקציה:
| songId | songName | artist | duration | plays | dayPlays | nightPlays |
|---|---|---|---|---|---|---|
| 1 | Hello | Adele | 4 | 800 | 500 | 300 |
| 2 | Shape | Ed | 3 | 600 | 400 | 200 |
| 3 | Bad Guy | Billie | 5 | 300 | 150 | 150 |
| 4 | One Dance | Drake | 2 | 350 | 250 | 100 |
ענו על 3 מתוך 6 הסעיפים שלפניכם:
כתבו שאילתה בשפת SQL המחזירה את כמות השירים בהם מספר ההשמעות הכולל (plays) גדול מ־500 וקטן מ 800.
כתבו שאילתה בשפת SQL המחזירה את מספר ההשמעות הגבוה ביותר ביום (dayPlays).
כתבו שאילתה בשפת SQL המחזירה את שמות השירים והאמנים בהם מספר ההשמעות בלילה גדול לפחות פי שניים ממספר ההשמעות ביום.
כתבו שאילתה בשפת SQL המחזירה את סך כל ההשמעות ביום (dayPlays) בכל השירים.
כתבו שאילתה בשפת SQL המחזירה את שמות השירים בהם משך השיר או קטן מ- 3 דקות או גדול מ- 5 דקות.
כתבו שאילתה בשפת SQL המחזירה את שמות האמנים שהשם שלהם מתחיל באות B או באות H.
◂ פתרון מלא לשאלה 7
סעיף א
SELECT COUNT(*) FROM SongsStats WHERE plays > 500 AND plays < 800; (בטבלת הדוגמה: 1)
מה נדרש – מספר (כמות) השירים, לא את השירים עצמם.
רעיון – הפונקציה המצרפת COUNT(*) סופרת את השורות שעברו את הסינון. התנאי "גדול מ־500 וקטן מ־800" הוא טווח פתוח – שני אי-שוויונות חזקים המחוברים ב-AND.
פתרון
SELECT COUNT(*)
FROM SongsStats
WHERE plays > 500 AND plays < 800;בדיקה – בטבלת הדוגמה: Hello (800) – לא, כי 800 אינו קטן מ־800; Shape (600) – כן; Bad Guy (300) ו-One Dance (350) – לא. התוצאה: 1.
טעות נפוצה: להשתמש ב-BETWEEN 500 AND 800 – BETWEEN כולל את הקצוות, ואז Hello (800) נספר בטעות.
סעיף ב
SELECT MAX(dayPlays) FROM SongsStats; (בטבלת הדוגמה: 500)
מה נדרש – ערך אחד: מספר ההשמעות ביום הגבוה ביותר.
רעיון – הפונקציה המצרפת MAX מחזירה את הערך הגדול ביותר בעמודה.
פתרון
SELECT MAX(dayPlays)
FROM SongsStats;בדיקה – ערכי dayPlays: 500, 400, 150, 250. התוצאה: 500.
סעיף ג
SELECT songName, artist FROM SongsStats WHERE nightPlays >= 2 * dayPlays; (בטבלת הדוגמה: אין שורות)
מה נדרש – שתי עמודות (songName, artist) של השירים שבהם nightPlays גדול לפחות פי 2 מ-dayPlays.
רעיון – אפשר להשוות בין שתי עמודות של אותה שורה ואף לבצע עליהן חישוב בתוך WHERE. "גדול לפחות פי שניים" פירושו nightPlays ≥ 2 · dayPlays.
פתרון
SELECT songName, artist
FROM SongsStats
WHERE nightPlays >= 2 * dayPlays;בדיקה – בטבלת הדוגמה אף שיר אינו מקיים את התנאי (למשל Hello: 300 ≥ 1000? לא; Bad Guy: 150 ≥ 300? לא), ולכן השאילתה מחזירה תוצאה ריקה – זו התשובה הנכונה עבור הדוגמה. בטבלה מורחבת שהוספנו לה את השירים Night Song (יום 100, לילה 200) ו-Late (יום 100, לילה 250) הוחזרו בדיוק שני השירים האלה (200 = 2·100 נכלל, כי "לפחות").
טעות נפוצה: להפוך את הכיוון (dayPlays >= 2 * nightPlays) או לכתוב nightPlays * 2 >= dayPlays.
סעיף ד
SELECT SUM(dayPlays) FROM SongsStats; (בטבלת הדוגמה: 1300)
מה נדרש – סכום עמודת dayPlays על כל השורות.
רעיון – הפונקציה המצרפת SUM, בלי WHERE (כל השירים).
פתרון
SELECT SUM(dayPlays)
FROM SongsStats;בדיקה – 500 + 400 + 150 + 250 = 1300. התוצאה: 1300.
טעות נפוצה: להשתמש ב-COUNT(dayPlays) – COUNT סופר שורות (4) ואינו מסכם ערכים.
סעיף ה
SELECT songName FROM SongsStats WHERE duration < 3 OR duration > 5; (בטבלת הדוגמה: One Dance)
מה נדרש – שמות השירים שמשכם מחוץ לטווח 3–5 דקות.
רעיון – "או קטן מ־3 או גדול מ־5" – שני תנאים המחוברים ב-OR (שיר לא יכול להיות גם קצר מ־3 וגם ארוך מ־5, ולכן AND היה מחזיר תמיד תוצאה ריקה). הגבולות 3 ו־5 אינם נכללים.
פתרון
SELECT songName
FROM SongsStats
WHERE duration < 3 OR duration > 5;בדיקה – משכים: 4, 3, 5, 2. רק One Dance (2) מקיים. התוצאה: One Dance. (3 ו־5 אינם נכללים: Shape ו-Bad Guy לא הוחזרו.)
טעות נפוצה: לחבר את התנאים ב-AND (duration < 3 AND duration > 5) – שאילתה כזו מחזירה תמיד תוצאה ריקה. (לעומת זאת duration NOT BETWEEN 3 AND 5 נכון.)
סעיף ו
SELECT DISTINCT artist FROM SongsStats WHERE artist LIKE 'B%' OR artist LIKE 'H%'; (בטבלת הדוגמה: Billie)
מה נדרש – שמות האמנים ששמם מתחיל ב-B או ב-H.
רעיון – האופרטור LIKE עם תבנית: 'B%' פירושו "מתחיל ב-B ואחריו כל רצף תווים". שני התנאים מחוברים ב-OR. DISTINCT מונע הופעה כפולה של אמן שיש לו כמה שירים (לא חובה, אבל מתאים ל"שמות האמנים").
פתרון
SELECT DISTINCT artist
FROM SongsStats
WHERE artist LIKE 'B%' OR artist LIKE 'H%';ב-Microsoft Access תו ה"כל רצף" הוא * במקום %: WHERE artist LIKE 'B*' OR artist LIKE 'H*'.
בדיקה – האמנים: Adele, Ed, Billie, Drake. רק Billie מתחיל ב-B ואין אמן שמתחיל ב-H. התוצאה: Billie. בטבלה מורחבת עם האמנים Halsey ו-Bruno הוחזרו Billie, Halsey, Bruno.
טעות נפוצה: לכתוב artist = 'B%' (השוואה רגילה, ללא LIKE – מחפש שם שהוא בדיוק "B%"), או LIKE 'B%' OR 'H%' בלי לחזור על שם העמודה.
פרק שלישי
ענו על אחת מן השאלות 9-8:
שאלה 8 · ASP.NET ומסד נתונים – בדיקת כרטיס (השלמת קוד)
בטופס באתר להזמנת כרטיסים נדרש המשתמש להזין קוד משתמש וסוג כרטיס:
<input type="text" name="userCode" id="userCode"/>
<input type="text" name="ticketType" id="ticketType"/>במסד הנתונים של האתר קיימת טבלה בשם tickets ובה שתי עמודות:
userCode (טקסט), קוד משתמש (ייחודי)
ticketType (טקסט), קוד הכרטיס אותו עליו לקנות
דוגמה לתוכן הטבלה:
| userCode | ticketType |
|---|---|
| A123 | Regular |
| B321 | VIP |
לפניכם קטע קוד חלקי של פעולה בשם CheckTicket שמטרתה לבדוק את תקינות הנתונים שהוזנו על ידי המשתמש. בהתאם לתוצאות הבדיקה, יש להפנות את המשתמש לעמוד מתאים לפי הכללים הבאים:
עליכם להשלים את הקוד החסר.
protected void CheckTicket(string connectionString)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format(
"SELECT * FROM tickets WHERE userCode = {0}'",
Request.Form["userCode"]);
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// *************** השלימו כאן ***************
}עליכם להשלים את הקוד החסר.
◂ פתרון מלא לשאלה 8
פתרון
if (ds.Tables[0].Rows.Count == 0) Response.Redirect("notFound.aspx");
else if (ds.Tables[0].Rows[0]["ticketType"].ToString() != Request.Form["ticketType"]) Response.Redirect("wrongTicket.aspx");
else Response.Redirect("success.aspx");
מה נדרש – להשלים את סוף הפעולה: לפי תוצאת השאילתה שכבר נמצאת ב-ds, להפנות לאחד משלושת העמודים.
רעיון
adapter.Fill(ds) התוצאה נמצאת בטבלה ds.Tables[0].ds.Tables[0].Rows.Count הוא 0 – הקוד לא קיים ⇐ notFound.aspx.ds.Tables[0].Rows[0]. משווים את הערך בעמודה ticketType לסוג הכרטיס שהמשתמש הזין בטופס – Request.Form["ticketType"]. אם שונים ⇐ wrongTicket.aspx, אחרת ⇐ success.aspx.פתרון – הקוד להשלמה (במקום ההערה "השלימו כאן"):
if (ds.Tables[0].Rows.Count == 0)
Response.Redirect("notFound.aspx");
else if (ds.Tables[0].Rows[0]["ticketType"].ToString() != Request.Form["ticketType"])
Response.Redirect("wrongTicket.aspx");
else
Response.Redirect("success.aspx");הערה על השאילתה המודפסת: במחרוזת "SELECT * FROM tickets WHERE userCode = {0}'" חסר הגרש הפותח לפני {0}. כיוון ש-userCode הוא טקסט, השאילתה הנכונה היא:
command.CommandText = string.Format(
"SELECT * FROM tickets WHERE userCode = '{0}'",
Request.Form["userCode"]);בדיקה – ההשלמה עם DataSet שמולא בתוצאת השאילתה על טבלת הדוגמה:
| userCode | ticketType שהוזן | דף |
|---|---|---|
| A123 | Regular | success.aspx |
| B321 | VIP | success.aspx |
| A123 | VIP | wrongTicket.aspx |
| B321 | Regular | wrongTicket.aspx |
| C999 | VIP | notFound.aspx |
השאילתה עצמה (עם הגרשים): עבור 'A123' מוחזרת השורה A123 | Regular, ועבור 'C999' – אין שורות.
טעות נפוצה: לגשת ל-ds.Tables[0].Rows[0] לפני שבודקים שיש שורות – כשהקוד לא קיים זו שגיאת ריצה. טעות נוספת: להשוות Rows[0]["ticketType"] (מטיפוס object) ישירות למחרוזת בלי ToString().
if (ds.Tables[0].Rows.Count == 0)
Response.Redirect("notFound.aspx");
else if (ds.Tables[0].Rows[0]["ticketType"].ToString() != Request.Form["ticketType"])
Response.Redirect("wrongTicket.aspx");
else
Response.Redirect("success.aspx");שאלה 9 · ASP.NET ו-SQL – שירים פופולריים ביום (השלמת CommandText)
שאלה זו מתייחסת לטבלת הנתונים SongsStats המוצגת בשאלה 7. לפניכם פעולה בצד שרת המקבלת מחרוזת חיבור למסד הנתונים:
protected void PopularSongs(string connectionString)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.Connection = connection;
command.CommandText =____________
// *************** השלימו כאן ***************
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
Response.Write("Number of songs: " + ds.Tables[0].Rows.Count);
}יש להשלים את הפקודה CommandText כך שתבצע את השאילתה הבאה:
הפעולה מחזירה את שם השיר (songName) ואת מספר ההשמעות (plays) של שירים בהם מספר ההשמעות ביום גדול ממספר ההשמעות בלילה וגם האות הראשונה בשם של השיר זהה לאות הראשונה בשם של האומן.
יש להשלים את הפקודה CommandText כך שתבצע את השאילתה הבאה: הפעולה מחזירה את שם השיר (songName) ואת מספר ההשמעות (plays) של שירים בהם מספר ההשמעות ביום גדול ממספר ההשמעות בלילה וגם האות הראשונה בשם של השיר זהה לאות הראשונה בשם של האומן.
◂ פתרון מלא לשאלה 9
פתרון
command.CommandText = "SELECT songName, plays FROM SongsStats WHERE dayPlays > nightPlays AND LEFT(songName, 1) = LEFT(artist, 1)"; (על טבלת הדוגמה יודפס Number of songs: 0)
מה נדרש – לכתוב מחרוזת SQL ולהציב אותה ב-command.CommandText.
רעיון
SELECT songName, plays – שתי העמודות המבוקשות, מהטבלה SongsStats.dayPlays > nightPlays (גדול ממש) – השוואה בין שתי עמודות של אותה שורה.LEFT(str, 1) מחזירה את התו הראשון (ב-SQL Server וב-Access; אפשר גם SUBSTRING(songName, 1, 1) ב-SQL Server או Mid(songName, 1, 1) ב-Access).פתרון
command.CommandText = "SELECT songName, plays FROM SongsStats " +
"WHERE dayPlays > nightPlays AND LEFT(songName, 1) = LEFT(artist, 1)";(המחרוזת מפוצלת לשתי שורות בעזרת + רק לנוחות הקריאה; אפשר לכתוב אותה בשורה אחת.)
אותה לוגיקה בכתיב SQL אחר, שבו במקום LEFT משתמשים ב-substr:
SELECT songName, plays
FROM SongsStats
WHERE dayPlays > nightPlays AND substr(songName, 1, 1) = substr(artist, 1, 1);בדיקה – על טבלת הדוגמה משאלה 7:
| songName | artist | dayPlays > nightPlays ? | אות ראשונה זהה? | נבחר? |
|---|---|---|---|---|
| Hello | Adele | 500 > 300 כן | H ≠ A | לא |
| Shape | Ed | 400 > 200 כן | S ≠ E | לא |
| Bad Guy | Billie | 150 > 150 לא | B = B | לא |
| One Dance | Drake | 250 > 100 כן | O ≠ D | לא |
השאילתה מחזירה 0 שורות, ולכן הפעולה תדפיס Number of songs: 0. בטבלה מורחבת שהוספנו לה את Halo/Hozier (יום 600, לילה 300), Easy/Ed (יום 300, לילה 100) ו-Dreams/Drake (יום 200, לילה 300) הוחזרו Halo | 900 ו-Easy | 400 (Dreams לא, כי יש בו יותר השמעות בלילה).
טעות נפוצה: לכתוב songName LIKE artist + '%' או להשוות את השמות כולם (songName = artist) במקום את האות הראשונה בלבד; לשכוח את המירכאות סביב מחרוזת ה-SQL ואת ; בסוף שורת ה-C#.
command.CommandText = "SELECT songName, plays FROM SongsStats " +
"WHERE dayPlays > nightPlays AND LEFT(songName, 1) = LEFT(artist, 1)";טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | ב. להכיל את הבקשה שנשלחה מהדפדפן (מהלקוח) לשרת |
| 2 | - | SELECT songName FROM Songs WHERE plays > 1000 AND type = 'Pop' AND releaseYear = 2020; |
| 3 | - | טבלה עם מסגרת, עמודה אחת ו־6 שורות, מלמעלה למטה: 1, 2, Buzz, 4, 5, Fizz |
| 4 | - | (1) i < originalCode.length |
| 5 | - | if (age >= 18 && isMember && visits >= 10) Response.Redirect("proWorkout.aspx"); |
| 6 | - | אם num % 5 != 0 מחזירים false; אחרת מחשבים את סכום הספרות בלולאה (sum += n % 10; n /= 10) ומחזירים sum % 7 == 0. |
| 7 | א | SELECT COUNT(*) FROM SongsStats WHERE plays > 500 AND plays < 800; (בטבלת הדוגמה: 1) |
| ב | SELECT MAX(dayPlays) FROM SongsStats; (בטבלת הדוגמה: 500) | |
| ג | SELECT songName, artist FROM SongsStats WHERE nightPlays >= 2 * dayPlays; (בטבלת הדוגמה: אין שורות) | |
| ד | SELECT SUM(dayPlays) FROM SongsStats; (בטבלת הדוגמה: 1300) | |
| ה | SELECT songName FROM SongsStats WHERE duration < 3 OR duration > 5; (בטבלת הדוגמה: One Dance) | |
| ו | SELECT DISTINCT artist FROM SongsStats WHERE artist LIKE 'B%' OR artist LIKE 'H%'; (בטבלת הדוגמה: Billie) | |
| 8 | - | if (ds.Tables[0].Rows.Count == 0) Response.Redirect("notFound.aspx"); |
| 9 | - | command.CommandText = "SELECT songName, plays FROM SongsStats WHERE dayPlays > nightPlays AND LEFT(songName, 1) = LEFT(artist, 1)"; (על טבלת הדוגמה יודפס Number of songs: 0) |