מתכונת 7 במדעי המחשב - תכנות באינטרנט 899372
נבחנים אקסטרניים · שאלון 899372 · 9 שאלות · 2 שעות · פתרון מלא לכל סעיף
מבחן מתכונת במדעי המחשב, תכנות באינטרנט, במבנה של בחינת הבגרות. כל שאלה בו בנויה כמו שאלה מבגרות אחרת. לכל סעיף יש תשובה ופתרון מלא, וכל קוד מופיע ב-Java וב-C#. פתרו בזמן של הבחינה, ורק אחר כך פתחו את הפתרונות.
הוראות הבחינה
א. משך הבחינה: שעתיים.
ב. מבנה השאלון ומפתח הערכה: בשאלון זה שלושה פרקים.
פרק ראשון — (10x3) — 30 נקודות
פרק שני — (20x2)+(10x1) — 50 נקודות
פרק שלישי — (20x1) — 20 נקודות
סך הכול — 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
יש לכתוב במחברת הבחינה בלבד, יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
פרק ראשון
ענו על שלוש השאלות 3-1 (לכל שאלה – 10 נקודות).
שאלה 1 · מונה כניסות לאתר – Application
באתר של ספרייה עירונית רוצים להציג בכל דף את מספר הכניסות לאתר מאז שהאתר הופעל. כל המבקרים באתר צריכים לראות את אותו מונה. באיזה אובייקט בצד השרת מתאים לשמור את המונה?
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד שלפניכם.
א. Session
ב. Request.Form
ג. Response
ד. Application
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד.
◂ פתרון מלא לשאלה 1
פתרון
ד. Application
מה נדרש – לבחור את האובייקט בצד השרת שבו שומרים מידע משותף לכל המבקרים באתר.
רעיון – בשרת ASP.NET יש שני אובייקטים לשמירת מידע בין בקשות ובין דפים:
מונה כניסות שכל המבקרים רואים חייב להיות משותף – לכן Application.
פתרון – נעבור על האפשרויות:
Response.Write, Response.Redirect); אינו שומר מידע. לא מתאים.שימוש אפשרי בקוד בצד השרת:
if (Application["count"] == null)
Application["count"] = 0;
Application["count"] = (int)Application["count"] + 1;
Response.Write("מספר הכניסות לאתר: " + Application["count"]);תשובה: ד.
בדיקה – שני מבקרים (דנה נכנסה פעמיים, יוסי פעם אחת): המונה ב־Application מגיע ל־3 ושני המבקרים רואים אותו, ואילו מונה שנשמר ב־Session של יוסי מראה רק 1.
טעות נפוצה: לבחור Session כי "הוא שומר מידע בין דפים" – נכון, אבל רק עבור משתמש אחד, ולכן כל מבקר היה רואה מונה אחר.
שאלה 2 · שאילתת SQL – טיסות זולות לרומא
במסד נתונים של אתר להזמנת טיסות מוגדרת טבלה בשם Flights ובה נתוני טיסות. בטבלה העמודות הבאות:
כתבו שאילתה בשפת SQL המחזירה את קוד הטיסה ואת המחיר של הטיסות ליעד Rome שמחירן נמוך מ־800 ונותרו בהן לפחות 10 מקומות פנויים.
כתבו שאילתה בשפת SQL המחזירה את קוד הטיסה ואת המחיר של הטיסות ליעד Rome שמחירן נמוך מ־800 ונותרו בהן לפחות 10 מקומות פנויים.
◂ פתרון מלא לשאלה 2
פתרון
SELECT flightCode, price FROM Flights WHERE destination = 'Rome' AND price < 800 AND seatsLeft >= 10;
מה נדרש – להחזיר שתי עמודות (flightCode ו-price) של הטיסות המקיימות שלושה תנאים יחד.
רעיון – אחרי SELECT כותבים את שתי העמודות, מופרדות בפסיק. ב-WHERE מחברים את שלושת התנאים ב-AND:
destination = 'Rome' – טקסט בין גרשיים בודדים.price < 800 – "נמוך מ־800": 800 עצמו אינו נכלל.seatsLeft >= 10 – "לפחות 10": 10 כן נכלל, ולכן >=.פתרון
SELECT flightCode, price
FROM Flights
WHERE destination = 'Rome' AND price < 800 AND seatsLeft >= 10;בדיקה – השאילתה על טבלה קטנה לדוגמה:
| flightCode | destination | price | seatsLeft | נבחר? |
|---|---|---|---|---|
| LY381 | Rome | 720 | 14 | כן |
| AZ809 | Rome | 800 | 30 | לא (800 אינו נמוך מ־800) |
| IZ211 | Rome | 650 | 10 | כן (בדיוק 10 – "לפחות 10") |
| W62311 | Rome | 390 | 9 | לא (פחות מ־10 מקומות) |
| LY315 | London | 700 | 40 | לא (יעד אחר) |
| FR6122 | Rome | 799 | 0 | לא (אין מקומות) |
התוצאה: (LY381, 720), (IZ211, 650).
טעות נפוצה: לכתוב seatsLeft > 10 – כך הטיסה IZ211 עם 10 מקומות בדיוק לא תוחזר, למרות ש"לפחות 10" כולל את 10.
שאלה 3 · שאילתת SELECT עם תנאי טקסט ותנאי מספרי
במסד נתונים של חברה להפקת הופעות מוגדרת טבלה בשם Concerts ובה פרטי ההופעות. בטבלה יש ארבע עמודות:
א. שם המבצע (performer).
ב. העיר שבה התקיימה ההופעה (city), באנגלית, למשל Haifa.
ג. מחיר כרטיס בשקלים (price).
ד. מספר הכרטיסים שנמכרו להופעה (tickets).
כתבו שאילתה בשפת SQL המאחזרת את שמות המבצעים ואת מחיר הכרטיס, בהופעות שהתקיימו בעיר Haifa ושנמכרו להן 2,000 כרטיסים לפחות.
כתבו שאילתה בשפת SQL המאחזרת את שמות המבצעים ואת מחיר הכרטיס, בהופעות שהתקיימו בעיר Haifa ושנמכרו להן 2,000 כרטיסים לפחות.
◂ פתרון מלא לשאלה 3
פתרון
SELECT performer, price FROM Concerts WHERE city = 'Haifa' AND tickets >= 2000
מה נדרש: שאילתה שמחזירה שתי עמודות (performer, price) רק עבור הופעות שמקיימות שני תנאים.
רעיון:
SELECT performer, price – רק העמודות המבוקשות.FROM Concerts – שם הטבלה.WHERE עם שני תנאים מחוברים ב-AND:city = 'Haifa' – ערך טקסט נכתב בין גרשים בודדים (');tickets >= 2000 ("לפחות" – גם 2000 בדיוק נכלל).פתרון:
SELECT performer, price
FROM Concerts
WHERE city = 'Haifa' AND tickets >= 2000בדיקה: השאילתה על טבלה לדוגמה (בשאלה אין שורות) עם שש הופעות: ארבע ב-Haifa (5200, 2000, 1999 ו-900 כרטיסים) ושתיים בערים אחרות (אחת מהן עם 8000 כרטיסים). התקבלו רק שתי שורות: ההופעה עם 5200 כרטיסים (מחיר 180) וההופעה עם 2000 כרטיסים בדיוק (מחיר 250). ההופעה עם 1999 כרטיסים לא נבחרה, וגם ההופעות בערים אחרות לא נבחרו, אף שנמכרו בהן הרבה כרטיסים.
טעות נפוצה: לכתוב tickets > 2000 (ואז הופעה עם 2000 כרטיסים בדיוק לא תיבחר), או לשכוח את הגרשים סביב 'Haifa'.
פרק שני
ענו על שלוש שאלות: על שאלה 4 (חובה – 10 נקודות) ועל שתיים מן השאלות 7-5 (לכל שאלה – 20 נקודות).
שאלה 4 · בדיקת מספר טלפון נייד ב-JavaScript
בטופס הזמנה באתר של פיצרייה ישנו שדה למילוי עבור מספר הטלפון הנייד של הלקוח, הרשום בצד השרת באופן הבא:
<input type="text" maxlength="10" name="phone" id="phone"/>לפניכם פונקציה ב-javascript שמבצעת בדיקה האם מספר הטלפון שהוקלד תקין.
מספר טלפון נייד תקין חייב להכיל מחרוזת בעלת 10 תווים בדיוק, שני התווים הראשונים בה הם 0 ו-5 (בסדר זה), וכל שאר התווים הם ספרות.
לדוגמה: 0521234567 – תקין; 0721234567 – לא תקין; 052-123456 – לא תקין.
בפונקציה חסרים חמישה ביטויים המסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (5), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
function isValidPhone()
{
var x = document.getElementById(____(1)____).value;
if (____(2)________)
return false;
if (x.charAt(0) != '0' || ____(3)_____)
return false;
for (var i=2; i<x.length; i++)
{
if (____(4)_____)
return ____(5)____;
}
return true;
}בפונקציה חסרים חמישה ביטויים המסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (5), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
◂ פתרון מלא לשאלה 4
פתרון
(1) "phone"
(2) x.length != 10
(3) x.charAt(1) != '5'
(4) x.charAt(i) < '0' || x.charAt(i) > '9'
(5) false
מה נדרש – להשלים 5 ביטויים בפונקציה שמחזירה true רק אם בשדה phone יש 10 תווים בדיוק, שמתחילים ב-05, וכולם ספרות.
רעיון – לקרוא את ערך השדה לפי ה-id שלו; לפסול אורך שאינו 10; לפסול אם התו הראשון אינו 0 או התו השני אינו 5; ואז לעבור על שאר התווים (מהמקום 2, כי שני הראשונים כבר נבדקו) ולהחזיר false ברגע שמוצאים תו שאינו ספרה. אם הלולאה הסתיימה – המספר תקין.
פתרון
| מספר | הביטוי החסר | הסבר |
|---|---|---|
| (1) | "phone" | getElementById מקבל את ה-id של הרכיב כמחרוזת (במירכאות). |
| (2) | x.length != 10 | נדרשים 10 תווים בדיוק. בגלל maxlength="10" אפשר גם x.length < 10, אבל != 10 מגן גם על קלט ארוך שעקף את maxlength. |
| (3) | x.charAt(1) != '5' | התנאי כולו: התו הראשון אינו 0 או התו השני אינו 5 ⇐ לא תקין. |
| (4) | x.charAt(i) < '0' || x.charAt(i) > '9' | התו במקום i אינו ספרה. |
| (5) | false | נמצא תו שאינו ספרה ⇐ המספר לא תקין. |
גם ביטויים שקולים מתקבלים, למשל ב-(4) !(x.charAt(i) >= '0' && x.charAt(i) <= '9'), וב-(3) x[1] != '5'.
הפונקציה המלאה:
function isValidPhone()
{
var x = document.getElementById("phone").value;
if (x.length != 10)
return false;
if (x.charAt(0) != '0' || x.charAt(1) != '5')
return false;
for (var i=2; i<x.length; i++)
{
if (x.charAt(i) < '0' || x.charAt(i) > '9')
return false;
}
return true;
}בדיקה:
| קלט | תוצאה |
|---|---|
0521234567 | true |
0500000000 | true |
0721234567 | false (התו השני 7) |
5521234567 | false (התו הראשון 5) |
052123456 (9 תווים) | false |
05212a4567 | false |
052-123456 | false |
"" (ריק) | false |
בנוסף בדקנו את הפונקציה מול ההגדרה על כל המחרוזות מעל {0, 5, 9, a} עד אורך 10 (1,398,101 מחרוזות) – התוצאה נכונה בכולן.
טעות נפוצה: לכתוב ב-(3) && במקום || בתנאי כולו (או לחשוב שצריך x.charAt(1) == '5') – התנאי צריך להיות "אחד מהשניים שגוי", ולכן || עם !=. טעות נוספת: לכתוב phone בלי מירכאות.
שאלה 5 · ניתוב בין דפים לפי משתני Session – קיר טיפוס
באתר של מתחם קיר הטיפוס "פסגה" נרשמים מטפסים לפני הכניסה. לאחר ההרשמה האתר מעביר כל מטפס לדף המתאים לו, ולשם כך משתמש במספר משתני Session:
בהתבסס על משתנים אלה, המשתמש עובר לדף מתאים לפי החוקיות הבאה:
– אם parent_ok הוא true וגם לפחות אחד משני התנאים הבאים מתקיים:
climbs גדול או שווה ל-8 או height גדול או שווה ל-160,
המטפס מועבר לדף הקיר המתקדם advancedWall.aspx.
– אחרת, אם parent_ok הוא true וגם height גדול או שווה ל-120, המטפס מועבר לדף קיר המתחילים beginnersWall.aspx.
– שאר המטפסים מועברים לדף המידע infoPage.aspx.
כתבו קוד המתאים לדרישות.
כתבו קוד המתאים לדרישות.
◂ פתרון מלא לשאלה 5
פתרון
קוראים את שלושת משתני ה-Session עם המרה, ואז: if (parentOk && (climbs >= 8 || height >= 160)) Response.Redirect("advancedWall.aspx"); else if (parentOk && height >= 120) Response.Redirect("beginnersWall.aspx"); else Response.Redirect("infoPage.aspx");
מה נדרש: קוד צד שרת (C#) שמעביר את המטפס לאחד משלושה דפים לפי ערכי שלושה משתני Session.
רעיון:
(int) לגובה ולמספר הטיפוסים, (bool) לאישור ההורים.||) חייב להיות בתוך סוגריים.פתרון (בקובץ ה-code behind של הדף):
protected void Page_Load(object sender, EventArgs e)
{
int height = (int)Session["height"];
bool parentOk = (bool)Session["parent_ok"];
int climbs = (int)Session["climbs"];
if (parentOk && (climbs >= 8 || height >= 160))
Response.Redirect("advancedWall.aspx");
else if (parentOk && height >= 120)
Response.Redirect("beginnersWall.aspx");
else
Response.Redirect("infoPage.aspx");
}בדיקה: בכל הצירופים של הערכים הקוד מפנה לדף הנכון, לפי הכללים שבשאלה. כמה דוגמאות:
| height | parent_ok | climbs | הדף |
|---|---|---|---|
| 150 | true | 10 | advancedWall.aspx (8 טיפוסים ומעלה) |
| 165 | true | 0 | advancedWall.aspx (גובה 160 ומעלה) |
| 150 | true | 2 | beginnersWall.aspx |
| 110 | true | 9 | advancedWall.aspx (הגובה קטן, אבל 9 טיפוסים) |
| 110 | true | 2 | infoPage.aspx |
| 170 | false | 12 | infoPage.aspx (אין אישור הורים) |
טעות נפוצה:
parentOk && climbs >= 8 || height >= 160 בלי סוגריים – בגלל ש-&& קודם ל-||, מטפס גבוה בלי אישור הורים היה מועבר לקיר המתקדם.protected void Page_Load(object sender, EventArgs e)
{
int height = (int)Session["height"];
bool parentOk = (bool)Session["parent_ok"];
int climbs = (int)Session["climbs"];
if (parentOk && (climbs >= 8 || height >= 160))
Response.Redirect("advancedWall.aspx");
else if (parentOk && height >= 120)
Response.Redirect("beginnersWall.aspx");
else
Response.Redirect("infoPage.aspx");
}שאלה 6 · מספר מדרגות – הפרש 1 בין ספרות סמוכות
נגדיר מספר מדרגות – מספר שלם חיובי בעל שתי ספרות לפחות, שבו ההפרש בין כל שתי ספרות סמוכות הוא בדיוק 1 (הספרה הבאה גדולה ב-1 או קטנה ב-1 מהספרה הקודמת).
דוגמאות למספרי מדרגות: 4565, 10, 98789, 3210
דוגמאות למספרים שאינם מספרי מדרגות: 4566, 1357, 7, 120
כתבו פונקציה בשם isStairs בצד שרת המקבלת מספר שלם חיובי ומחזירה אמת אם המספר הוא מספר מדרגות. אחרת, מחזירה שקר.
כתבו פונקציה בשם isStairs בצד שרת המקבלת מספר שלם חיובי ומחזירה אמת אם המספר הוא מספר מדרגות. אחרת, מחזירה שקר.
◂ פתרון מלא לשאלה 6
פתרון
public bool isStairs(int num) – אם num < 10 מחזירים false; שומרים את הספרה האחרונה ב-prev, ובלולאה משווים כל ספרה d ל-prev: אם d - prev != 1 && prev - d != 1 מחזירים false; בסוף true.
מה נדרש: פונקציה ב-C# (צד שרת) שבודקת שבין כל שתי ספרות סמוכות במספר ההפרש הוא בדיוק 1, ושיש במספר לפחות שתי ספרות.
רעיון:
num < 10) אינו מספר מדרגות ⇐ מחזירים false מיד.prev את הספרה האחרונה ומסירים אותה. בכל סיבוב לוקחים את הספרה הבאה d (משמאל ל-prev) ובודקים שההפרש ביניהן הוא 1 או -1: d - prev == 1 או prev - d == 1. אם אף אחד מהם לא מתקיים – מחזירים false מיד.prev = d ומסירים את הספרה. אם הלולאה הסתיימה בלי false – כל הזוגות הסמוכים תקינים ⇐ true.Math.Abs(d - prev) != 1.)פתרון – הקוד המלא בלשונית C#:
public bool isStairs(int num)
{
if (num < 10)
return false;
int prev = num % 10;
num = num / 10;
while (num > 0)
{
int d = num % 10;
if (d - prev != 1 && prev - d != 1)
return false;
prev = d;
num = num / 10;
}
return true;
}בדיקה – מעקב על 4565 ועל 4566:
| num | prev | d | הפרש | פעולה |
|---|---|---|---|---|
| 456 | 5 | 6 | 1 | תקין |
| 45 | 6 | 5 | 1 | תקין |
| 4 | 5 | 4 | 1 | תקין ⇐ true |
ב-4566: prev=6, d=6 ⇐ הפרש 0 ⇐ false כבר בסיבוב הראשון.
על הדוגמאות שבשאלה: 4565, 10, 98789, 3210 ⇐ True; 4566, 1357, 7, 120 ⇐ False.
טעות נפוצה: לבדוק רק "עולה ב-1" (d - prev == 1) – אז 4565 יחזיר בטעות false; או לשכוח את המספרים החד-ספרתיים – בלי הבדיקה בהתחלה הלולאה לא מתבצעת והפונקציה תחזיר true עבור 7.
public bool isStairs(int num)
{
if (num < 10)
return false;
int prev = num % 10;
num = num / 10;
while (num > 0)
{
int d = num % 10;
if (d - prev != 1 && prev - d != 1)
return false;
prev = d;
num = num / 10;
}
return true;
}שאלה 7 · שאילתות SQL על טבלת חניונים (20 נקודות)
במסד הנתונים של עירייה יש טבלה ששמה ParkingLots המכילה את נתוני החניונים הציבוריים בעיר. העמודות בטבלה הן:
דוגמה לטבלה:
| lotName | spaces | hourPrice | morningCars | nightCars |
|---|---|---|---|---|
| "חניון התחנה" | 350 | 12 | 300 | 40 |
| "חניון השוק" | 120 | 8 | 100 | 30 |
| "חניון הים" | 200 | 15 | 60 | 150 |
| "חניון הספרייה" | 80 | 6 | 70 | 10 |
| "חניון האצטדיון" | 500 | 10 | 50 | 180 |
| "חניון המרכז" | 150 | 9 | 60 | 130 |
יש לבחור 2 מתוך 4 הסעיפים הבאים:
כתבו שאילתה בשפת SQL שמחזירה את מספר החניונים שיש בהם לפחות 200 מקומות חניה. דוגמה: בטבלה הנוכחית יוחזר הערך 3 (עבור חניון התחנה, חניון הים וחניון האצטדיון).
כתבו שאילתה בשפת SQL המחזירה את המחיר הגבוה ביותר של שעת חניה בעיר. דוגמה: בטבלה הנוכחית יוחזר הערך 15 ("חניון הים").
כתבו שאילתה בשפת SQL שמחזירה את שמות החניונים ואת מספר מקומות החניה בהם, בחניונים שבהם מספר המכוניות בשעות הלילה גדול מפי 2 ממספר המכוניות בשעות הבוקר.
כתבו שאילתה בשפת SQL שמחזירה את סך המכוניות בשעות הבוקר, בכל החניונים שבהם מחיר שעת חניה קטן מ-10 ש"ח. דוגמה: בטבלה הנוכחית יוחזר הערך 230 (100+70+60).
◂ פתרון מלא לשאלה 7
סעיף א
SELECT COUNT(*) AS bigLots FROM ParkingLots WHERE spaces >= 200;
מה נדרש: מספר החניונים (כמה שורות) שבהם spaces גדול או שווה ל-200.
רעיון: מסננים ב-WHERE את השורות עם spaces >= 200 ("לפחות" = גדול או שווה), וסופרים אותן ב-COUNT(*).
פתרון:
SELECT COUNT(*) AS bigLots
FROM ParkingLots
WHERE spaces >= 200;בדיקה: על טבלת הדוגמה: 350, 200, 500 עומדים בתנאי; 120, 80, 150 לא. התקבל 3, כמו בדוגמה.
טעות נפוצה: לכתוב spaces > 200 – אז חניון הים (בדיוק 200) לא ייספר ויתקבל 2.
סעיף ב
SELECT MAX(hourPrice) AS topPrice FROM ParkingLots;
מה נדרש: הערך הגדול ביותר בעמודה hourPrice.
רעיון: פונקציית הצבירה MAX מחזירה את הערך הגדול ביותר בעמודה. אין צורך ב-WHERE – בודקים את כל החניונים.
פתרון:
SELECT MAX(hourPrice) AS topPrice
FROM ParkingLots;בדיקה: המחירים הם 12, 8, 15, 6, 10, 9. התקבל 15, כמו בדוגמה.
טעות נפוצה: לכתוב SELECT hourPrice FROM ParkingLots WHERE hourPrice = MAX(hourPrice) – אי אפשר להשתמש בפונקציית צבירה בתוך WHERE.
סעיף ג
SELECT lotName, spaces FROM ParkingLots WHERE nightCars > 2 * morningCars;
מה נדרש: שם ומספר מקומות של כל חניון שבו nightCars > 2 · morningCars.
רעיון: בוחרים את העמודות lotName ו-spaces, ובתנאי WHERE משווים עמודה אחת לביטוי חשבוני על עמודה אחרת באותה שורה (2 * morningCars).
פתרון:
SELECT lotName, spaces
FROM ParkingLots
WHERE nightCars > 2 * morningCars;בדיקה: על טבלת הדוגמה:
| lotName | spaces |
|---|---|
| חניון הים | 200 |
| חניון האצטדיון | 500 |
| חניון המרכז | 150 |
(150 > 120, 180 > 100, 130 > 120; לעומת זאת 40 < 600, 30 < 200 ו-10 < 140.)
טעות נפוצה: לכתוב nightCars * 2 > morningCars – הכפל על העמודה הלא נכונה.
סעיף ד
SELECT SUM(morningCars) AS morningCheap FROM ParkingLots WHERE hourPrice < 10;
מה נדרש: סכום העמודה morningCars, רק בשורות שבהן hourPrice < 10.
רעיון: קודם WHERE מסנן את השורות (החניונים הזולים), ואחר כך פונקציית הצבירה SUM מחברת את morningCars בשורות שנשארו.
פתרון:
SELECT SUM(morningCars) AS morningCheap
FROM ParkingLots
WHERE hourPrice < 10;בדיקה: החניונים שמחירם קטן מ-10: חניון השוק (100), חניון הספרייה (70), חניון המרכז (60). חניון האצטדיון (בדיוק 10) לא נכלל. 100 + 70 + 60 = 230 – התוצאה 230, כמו בדוגמה.
טעות נפוצה: לשכוח את ה-WHERE – אז מתקבל סכום כל החניונים (640); או לכתוב <= 10 ולקבל 280.
פרק שלישי
ענו על שאלה אחת מן השאלות 9-8.
שאלה 8 · זיהוי לקוח לפי היסטוריית הזמנות
באתר של מסעדה המציעה משלוחים, הלקוח מקליד את מספר הטלפון שלו בשדה זה:
<input type="tel" name="phone" id="phone"/>בבסיס הנתונים של האתר קיימת טבלה בשם orders, ובה שורה לכל הזמנה שבוצעה. בטבלה שלוש עמודות:
| phone | orderDate | total |
|---|---|---|
| 050-1111111 | 10/01/2025 | 450 |
| 052-2222222 | 12/01/2025 | 120 |
| 050-1111111 | 03/02/2025 | 700 |
| 052-2222222 | 15/03/2025 | 300 |
| 054-3333333 | 20/03/2025 | 1000 |
לפניכם קטע קוד חלקי תקין של פעולה בשם CheckCustomer. יש להפנות את הלקוח לעמוד המתאים על פי החוקים הבאים:
protected void CheckCustomer(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From orders Where phone = '{0}'",
Request.Form["phone"]);
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("newCustomer.aspx");
}
else
{
int sum = 0;
foreach (DataRow dr in ds.Tables[0].Rows)
{
sum += int.Parse(dr["total"].ToString());
}
if (sum >= 1000)
{
Session["vip"] = true;
Response.Redirect("vip.aspx");
}
else
{
Response.Redirect("regular.aspx");
}
}
מה נדרש – להשלים את סוף הפעולה: לפי השורות שהשאילתה החזירה (כל ההזמנות של הטלפון שהוקלד) להחליט לאן להפנות.
רעיון
ds.Tables[0] מכיל את כל ההזמנות של הלקוח – יכולות להיות כמה שורות.Rows.Count == 0) ⇒ newCustomer.aspx.foreach על כל השורות וצוברים את total (ממירים: int.Parse(dr["total"].ToString())).Session["vip"] = true ואז vip.aspx; אחרת regular.aspx.פתרון – הקוד שנכתב במקום הכוכביות:
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("newCustomer.aspx");
}
else
{
int sum = 0;
foreach (DataRow dr in ds.Tables[0].Rows)
{
sum += int.Parse(dr["total"].ToString());
}
if (sum >= 1000)
{
Session["vip"] = true;
Response.Redirect("vip.aspx");
}
else
{
Response.Redirect("regular.aspx");
}
}הפעולה המלאה:
protected void CheckCustomer(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From orders Where phone = '{0}'",
Request.Form["phone"]);
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// ---- the missing code ----
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("newCustomer.aspx");
}
else
{
int sum = 0;
foreach (DataRow dr in ds.Tables[0].Rows)
{
sum += int.Parse(dr["total"].ToString());
}
if (sum >= 1000)
{
Session["vip"] = true;
Response.Redirect("vip.aspx");
}
else
{
Response.Redirect("regular.aspx");
}
}
}בדיקה – הפעולה המלאה על הטבלה orders מהשאלה:
| phone | הזמנות | סכום | הפניה | Session["vip"] |
|---|---|---|---|---|
| 050-1111111 | 450, 700 | 1150 | vip.aspx | true |
| 054-3333333 | 1000 | 1000 | vip.aspx | true |
| 052-2222222 | 120, 300 | 420 | regular.aspx | (לא נשמר) |
| 058-9999999 | – | – | newCustomer.aspx | (לא נשמר) |
הלקוח 054-3333333 בודק את הגבול: 1000 בדיוק הוא "1000 לפחות".
טעות נפוצה: לבדוק רק את השורה הראשונה (Rows[0]["total"]) – עבור 050-1111111 מתקבל 450, והלקוח יופנה בטעות ל־regular.aspx למרות שסכום הזמנותיו 1150. טעות נוספת: לאפס את sum בתוך הלולאה, או לכתוב sum > 1000.
protected void CheckCustomer(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From orders Where phone = '{0}'",
Request.Form["phone"]);
command.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// ---- the missing code ----
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("newCustomer.aspx");
}
else
{
int sum = 0;
foreach (DataRow dr in ds.Tables[0].Rows)
{
sum += int.Parse(dr["total"].ToString());
}
if (sum >= 1000)
{
Session["vip"] = true;
Response.Redirect("vip.aspx");
}
else
{
Response.Redirect("regular.aspx");
}
}
}שאלה 9 · ASP.NET ו-SQL – ציורים אהובים בגלריה (השלמת CommandText)
במסד הנתונים של אתר גלריה לאמנות יש טבלה ששמה Paintings. העמודות בטבלה הן:
דוגמה לטבלה:
| paintingId | title | painter | year | price | likes | dislikes |
|---|---|---|---|---|---|---|
| 1 | Sunset | Monet | 1890 | 5000 | 300 | 50 |
| 2 | Blue Sea | Dali | 1935 | 8000 | 200 | 100 |
| 3 | Garden | Klimt | 1905 | 7000 | 450 | 100 |
| 4 | Blue Ball | Chagall | 1950 | 6500 | 90 | 40 |
לפניכם פעולה בצד שרת המקבלת מחרוזת חיבור למסד הנתונים:
protected void LovedPaintings(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 paintings: " + ds.Tables[0].Rows.Count);
}יש להשלים את הפקודה CommandText כך שתבצע את השאילתה הבאה:
הפעולה מחזירה את שם הציור (title) ואת המחיר (price) של ציורים שבהם מספר ה"אהבתי" גדול מפי שלושה ממספר ה"לא אהבתי" וגם האות האחרונה בשם הציור זהה לאות האחרונה בשם הצייר.
יש להשלים את הפקודה CommandText כך שתבצע את השאילתה הבאה: הפעולה מחזירה את שם הציור (title) ואת המחיר (price) של ציורים שבהם מספר ה"אהבתי" גדול מפי שלושה ממספר ה"לא אהבתי" וגם האות האחרונה בשם הציור זהה לאות האחרונה בשם הצייר.
◂ פתרון מלא לשאלה 9
פתרון
command.CommandText = "SELECT title, price FROM Paintings WHERE likes > 3 * dislikes AND RIGHT(title, 1) = RIGHT(painter, 1)"; (על טבלת הדוגמה יודפס Number of paintings: 1)
מה נדרש – לכתוב מחרוזת SQL ולהציב אותה ב-command.CommandText.
רעיון
SELECT title, price – שתי העמודות המבוקשות, מהטבלה Paintings.likes > 3 * dislikes (גדול ממש) – השוואה בין שתי עמודות של אותה שורה.RIGHT(str, 1) מחזירה את התו האחרון (ב-SQL Server וב-Access).פתרון
command.CommandText = "SELECT title, price FROM Paintings " +
"WHERE likes > 3 * dislikes AND RIGHT(title, 1) = RIGHT(painter, 1)";(המחרוזת מפוצלת לשתי שורות בעזרת + רק לנוחות הקריאה; שימו לב לרווח בסוף החלק הראשון, אחרת יתקבל PaintingsWHERE.)
אותה לוגיקה בכתיב SQL אחר, שבו במקום RIGHT משתמשים ב-substr עם מיקום שלילי:
SELECT title, price
FROM Paintings
WHERE likes > 3 * dislikes AND substr(title, -1, 1) = substr(painter, -1, 1);בדיקה – על טבלת הדוגמה:
| title | painter | likes > 3·dislikes ? | אות אחרונה זהה? | נבחר? |
|---|---|---|---|---|
| Sunset | Monet | 300 > 150 כן | t = t | כן |
| Blue Sea | Dali | 200 > 300 לא | a ≠ i | לא |
| Garden | Klimt | 450 > 300 כן | n ≠ t | לא |
| Blue Ball | Chagall | 90 > 120 לא | l = l | לא |
השאילתה מחזירה שורה אחת – Sunset | 5000 – ולכן הפעולה תדפיס Number of paintings: 1. בטבלה מורחבת הוספנו את The Swan / Rubin עם 301 "אהבתי" ו־100 "לא אהבתי" – הוא הוחזר (301 > 300), ואילו ציור עם אותיות אחרונות שונות לא הוחזר גם כשהיו לו הרבה "אהבתי".
טעות נפוצה: להשתמש ב-LEFT במקום RIGHT, או לכתוב likes >= 3 * dislikes ("גדול מ..." הוא גדול ממש).
command.CommandText = "SELECT title, price FROM Paintings " +
"WHERE likes > 3 * dislikes AND RIGHT(title, 1) = RIGHT(painter, 1)";טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | ד. Application |
| 2 | - | SELECT flightCode, price FROM Flights WHERE destination = 'Rome' AND price < 800 AND seatsLeft >= 10; |
| 3 | - |
|
| 4 | - | (1) "phone" |
| 5 | - | קוראים את שלושת משתני ה-Session עם המרה, ואז: if (parentOk && (climbs >= 8 || height >= 160)) Response.Redirect("advancedWall.aspx"); else if (parentOk && height >= 120) Response.Redirect("beginnersWall.aspx"); else Response.Redirect("infoPage.aspx"); |
| 6 | - |
|
| 7 | א | SELECT COUNT(*) AS bigLots FROM ParkingLots WHERE spaces >= 200; |
| ב | SELECT MAX(hourPrice) AS topPrice FROM ParkingLots; | |
| ג | SELECT lotName, spaces FROM ParkingLots WHERE nightCars > 2 * morningCars; | |
| ד | SELECT SUM(morningCars) AS morningCheap FROM ParkingLots WHERE hourPrice < 10; | |
| 8 | - | if (ds.Tables[0].Rows.Count == 0) |
| 9 | - | command.CommandText = "SELECT title, price FROM Paintings WHERE likes > 3 * dislikes AND RIGHT(title, 1) = RIGHT(painter, 1)"; (על טבלת הדוגמה יודפס Number of paintings: 1) |