דילוג לתוכן המרכזי

מתכונת 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

העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד.

(10 נקודות)
◂ פתרון מלא לשאלה 1

פתרון

תשובה

ד. Application

מה נדרש – לבחור את האובייקט בצד השרת שבו שומרים מידע משותף לכל המבקרים באתר.

רעיון – בשרת ASP.NET יש שני אובייקטים לשמירת מידע בין בקשות ובין דפים:

•Session – אובייקט נפרד לכל משתמש (לכל דפדפן שמתחבר). מה שמשתמש אחד שומר בו אינו נראה למשתמש אחר.
•Application – אובייקט אחד לכל האתר, משותף לכל המשתמשים, וקיים כל עוד האתר פועל.

מונה כניסות שכל המבקרים רואים חייב להיות משותף – לכן Application.

פתרון – נעבור על האפשרויות:

•א. Session – כל מבקר היה מקבל מונה פרטי משלו, שסופר רק את הכניסות שלו. לא מתאים.
•ב. Request.Form – משמש לקריאת הערכים שנשלחו מטופס בבקשה הנוכחית; הוא אינו שומר דבר בין בקשות. לא מתאים.
•ג. Response – משמש לשליחת תשובה לדפדפן (למשל Response.Write, Response.Redirect); אינו שומר מידע. לא מתאים.
•ד. Application – נכון: מידע משותף לכל המשתמשים באתר.

שימוש אפשרי בקוד בצד השרת:

C#
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 ובה נתוני טיסות. בטבלה העמודות הבאות:

•flightId (מזהה הטיסה, מספר שלם)
•flightCode (קוד הטיסה, טקסט)
•airline (חברת התעופה, טקסט)
•destination (היעד, טקסט)
•durationMin (משך הטיסה בדקות, מספר שלם)
•price (מחיר הכרטיס בדולרים, מספר שלם)
•seatsLeft (מספר המקומות הפנויים, מספר שלם)

כתבו שאילתה בשפת SQL המחזירה את קוד הטיסה ואת המחיר של הטיסות ליעד Rome שמחירן נמוך מ־800 ונותרו בהן לפחות 10 מקומות פנויים.

כתבו שאילתה בשפת SQL המחזירה את קוד הטיסה ואת המחיר של הטיסות ליעד Rome שמחירן נמוך מ־800 ונותרו בהן לפחות 10 מקומות פנויים.

(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 כן נכלל, ולכן >=.

פתרון

SQL
SELECT flightCode, price
FROM Flights
WHERE destination = 'Rome' AND price < 800 AND seatsLeft >= 10;

בדיקה – השאילתה על טבלה קטנה לדוגמה:

flightCodedestinationpriceseatsLeftנבחר?
LY381Rome72014כן
AZ809Rome80030לא (800 אינו נמוך מ־800)
IZ211Rome65010כן (בדיוק 10 – "לפחות 10")
W62311Rome3909לא (פחות מ־10 מקומות)
LY315London70040לא (יעד אחר)
FR6122Rome7990לא (אין מקומות)

התוצאה: (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 כרטיסים לפחות.

(10 נקודות)
◂ פתרון מלא לשאלה 3

פתרון

תשובה

SELECT performer, price FROM Concerts WHERE city = 'Haifa' AND tickets >= 2000

מה נדרש: שאילתה שמחזירה שתי עמודות (performer, price) רק עבור הופעות שמקיימות שני תנאים.

רעיון:

•SELECT performer, price – רק העמודות המבוקשות.
•FROM Concerts – שם הטבלה.
•WHERE עם שני תנאים מחוברים ב-AND:
•"התקיימה בעיר Haifa" ⇐ city = 'Haifa' – ערך טקסט נכתב בין גרשים בודדים (');
•"נמכרו 2,000 כרטיסים לפחות" ⇐ tickets >= 2000 ("לפחות" – גם 2000 בדיוק נכלל).

פתרון:

SQL
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

בטופס הזמנה באתר של פיצרייה ישנו שדה למילוי עבור מספר הטלפון הנייד של הלקוח, הרשום בצד השרת באופן הבא:

HTML
<input type="text" maxlength="10" name="phone" id="phone"/>

לפניכם פונקציה ב-javascript שמבצעת בדיקה האם מספר הטלפון שהוקלד תקין.

מספר טלפון נייד תקין חייב להכיל מחרוזת בעלת 10 תווים בדיוק, שני התווים הראשונים בה הם 0 ו-5 (בסדר זה), וכל שאר התווים הם ספרות.

לדוגמה: 0521234567 – תקין; 0721234567 – לא תקין; 052-123456 – לא תקין.

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

JavaScript
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), בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.

(10 נקודות)
◂ פתרון מלא לשאלה 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'.

הפונקציה המלאה:

JavaScript
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;
}

בדיקה:

קלטתוצאה
0521234567true
0500000000true
0721234567false (התו השני 7)
5521234567false (התו הראשון 5)
052123456 (9 תווים)false
05212a4567false
052-123456false
"" (ריק)false

בנוסף בדקנו את הפונקציה מול ההגדרה על כל המחרוזות מעל {0, 5, 9, a} עד אורך 10 (1,398,101 מחרוזות) – התוצאה נכונה בכולן.

טעות נפוצה: לכתוב ב-(3) && במקום || בתנאי כולו (או לחשוב שצריך x.charAt(1) == '5') – התנאי צריך להיות "אחד מהשניים שגוי", ולכן || עם !=. טעות נוספת: לכתוב phone בלי מירכאות.

שאלה 5 · ניתוב בין דפים לפי משתני Session – קיר טיפוס

באתר של מתחם קיר הטיפוס "פסגה" נרשמים מטפסים לפני הכניסה. לאחר ההרשמה האתר מעביר כל מטפס לדף המתאים לו, ולשם כך משתמש במספר משתני Session:

•Session["height"]: מספר שלם המייצג את גובה המטפס בסנטימטרים.
•Session["parent_ok"]: משתנה בוליאני המציין האם הוגש למתחם אישור הורים חתום: כן (true) או לא (false).
•Session["climbs"]: מספר שלם המייצג את מספר הטיפוסים שהמטפס כבר השלים במתחם.

בהתבסס על משתנים אלה, המשתמש עובר לדף מתאים לפי החוקיות הבאה:

– אם parent_ok הוא true וגם לפחות אחד משני התנאים הבאים מתקיים:
climbs גדול או שווה ל-8 או height גדול או שווה ל-160,
המטפס מועבר לדף הקיר המתקדם advancedWall.aspx.
– אחרת, אם parent_ok הוא true וגם height גדול או שווה ל-120, המטפס מועבר לדף קיר המתחילים beginnersWall.aspx.
– שאר המטפסים מועברים לדף המידע infoPage.aspx.

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

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

(20 נקודות)
◂ פתרון מלא לשאלה 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.

רעיון:

1.קוראים כל משתנה Session עם המרה לטיפוס שלו: (int) לגובה ולמספר הטיפוסים, (bool) לאישור ההורים.
2.בכלל הראשון יש "וגם" בין parent_ok לבין "לפחות אחד" משני תנאים – לכן ה-"או" (||) חייב להיות בתוך סוגריים.
3.הכלל השני מתחיל ב"אחרת" – כלומר נבדק רק אם הכלל הראשון לא התקיים. לכן משתמשים ב-else if, ואין צורך לבדוק שוב שהמטפס לא מתאים לקיר המתקדם.
4.כל השאר (אין אישור הורים, או גובה מתחת ל-120) – else.

פתרון (בקובץ ה-code behind של הדף):

C#
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");
}

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

heightparent_okclimbsהדף
150true10advancedWall.aspx (8 טיפוסים ומעלה)
165true0advancedWall.aspx (גובה 160 ומעלה)
150true2beginnersWall.aspx
110true9advancedWall.aspx (הגובה קטן, אבל 9 טיפוסים)
110true2infoPage.aspx
170false12infoPage.aspx (אין אישור הורים)

טעות נפוצה:

•לכתוב parentOk && climbs >= 8 || height >= 160 בלי סוגריים – בגלל ש-&& קודם ל-||, מטפס גבוה בלי אישור הורים היה מועבר לקיר המתקדם.
•לבדוק את כלל קיר המתחילים לפני כלל הקיר המתקדם – אז מטפס בגובה 165 עם אישור היה נשלח לקיר המתחילים.
הקוד המלא
C#
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 בצד שרת המקבלת מספר שלם חיובי ומחזירה אמת אם המספר הוא מספר מדרגות. אחרת, מחזירה שקר.

(20 נקודות)
◂ פתרון מלא לשאלה 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#:

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:

numprevdהפרשפעולה
456561תקין
45651תקין
4541תקין ⇐ 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.

הקוד המלא
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;
}

שאלה 7 · שאילתות SQL על טבלת חניונים (20 נקודות)

במסד הנתונים של עירייה יש טבלה ששמה ParkingLots המכילה את נתוני החניונים הציבוריים בעיר. העמודות בטבלה הן:

•lotName (שם החניון) - מסוג טקסט
•spaces (מספר מקומות החניה בחניון) - מסוג מספר שלם
•hourPrice (מחיר שעת חניה בש"ח) - מסוג מספר שלם
•morningCars (מספר המכוניות הממוצע בחניון בשעות הבוקר) - מסוג מספר שלם
•nightCars (מספר המכוניות הממוצע בחניון בשעות הלילה) - מסוג מספר שלם

דוגמה לטבלה:

lotNamespaceshourPricemorningCarsnightCars
"חניון התחנה"3501230040
"חניון השוק"120810030
"חניון הים"2001560150
"חניון הספרייה"8067010
"חניון האצטדיון"5001050180
"חניון המרכז"150960130

יש לבחור 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(*).

פתרון:

SQL
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 – בודקים את כל החניונים.

פתרון:

SQL
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).

פתרון:

SQL
SELECT lotName, spaces
FROM ParkingLots
WHERE nightCars > 2 * morningCars;

בדיקה: על טבלת הדוגמה:

lotNamespaces
חניון הים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 בשורות שנשארו.

פתרון:

SQL
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 · זיהוי לקוח לפי היסטוריית הזמנות

באתר של מסעדה המציעה משלוחים, הלקוח מקליד את מספר הטלפון שלו בשדה זה:

HTML
<input type="tel" name="phone" id="phone"/>

בבסיס הנתונים של האתר קיימת טבלה בשם orders, ובה שורה לכל הזמנה שבוצעה. בטבלה שלוש עמודות:

•phone – מספר הטלפון של הלקוח, משתנה מסוג טקסט
•orderDate – תאריך ההזמנה, משתנה מסוג טקסט
•total – סכום ההזמנה בש"ח, משתנה מסוג מספר שלם
phoneorderDatetotal
050-111111110/01/2025450
052-222222212/01/2025120
050-111111103/02/2025700
052-222222215/03/2025300
054-333333320/03/20251000

לפניכם קטע קוד חלקי תקין של פעולה בשם CheckCustomer. יש להפנות את הלקוח לעמוד המתאים על פי החוקים הבאים:

•אם אין בבסיס הנתונים אף הזמנה עם מספר הטלפון שהוקלד, הפעולה תפנה לעמוד newCustomer.aspx
•אם סכום כל ההזמנות של הלקוח הוא 1000 ש"ח לפחות, הפעולה תשמור את הערך true במשתנה Session["vip"] ותפנה לעמוד vip.aspx
•אחרת, הפעולה תפנה לעמוד regular.aspx
C#
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();
                    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
                    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
}

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

(20 נקודות)
◂ פתרון מלא לשאלה 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())).
•סכום ≥ 1000 ⇒ Session["vip"] = true ואז vip.aspx; אחרת regular.aspx.

פתרון – הקוד שנכתב במקום הכוכביות:

C#
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");
    }
}

הפעולה המלאה:

C#
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-1111111450, 7001150vip.aspxtrue
054-333333310001000vip.aspxtrue
052-2222222120, 300420regular.aspx(לא נשמר)
058-9999999––newCustomer.aspx(לא נשמר)

הלקוח 054-3333333 בודק את הגבול: 1000 בדיוק הוא "1000 לפחות".

טעות נפוצה: לבדוק רק את השורה הראשונה (Rows[0]["total"]) – עבור 050-1111111 מתקבל 450, והלקוח יופנה בטעות ל־regular.aspx למרות שסכום הזמנותיו 1150. טעות נוספת: לאפס את sum בתוך הלולאה, או לכתוב sum > 1000.

הקוד המלא
C#
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 (מספר הגולשים שסימנו "לא אהבתי", מספר שלם)

דוגמה לטבלה:

paintingIdtitlepainteryearpricelikesdislikes
1SunsetMonet1890500030050
2Blue SeaDali19358000200100
3GardenKlimt19057000450100
4Blue BallChagall195065009040

לפניכם פעולה בצד שרת המקבלת מחרוזת חיבור למסד הנתונים:

C#
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) של ציורים שבהם מספר ה"אהבתי" גדול מפי שלושה ממספר ה"לא אהבתי" וגם האות האחרונה בשם הציור זהה לאות האחרונה בשם הצייר.

(20 נקודות)
◂ פתרון מלא לשאלה 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 (גדול ממש) – השוואה בין שתי עמודות של אותה שורה.
•תנאי שני: האות האחרונה של title שווה לאות האחרונה של painter. הפונקציה RIGHT(str, 1) מחזירה את התו האחרון (ב-SQL Server וב-Access).
•שני התנאים מחוברים ב-AND.
•כל השאילתה היא מחרוזת C# – בתוך מירכאות, ובסוף שורת ה-C# נקודה-פסיק.

פתרון

C#
command.CommandText = "SELECT title, price FROM Paintings " +
                      "WHERE likes > 3 * dislikes AND RIGHT(title, 1) = RIGHT(painter, 1)";

(המחרוזת מפוצלת לשתי שורות בעזרת + רק לנוחות הקריאה; שימו לב לרווח בסוף החלק הראשון, אחרת יתקבל PaintingsWHERE.)

אותה לוגיקה בכתיב SQL אחר, שבו במקום RIGHT משתמשים ב-substr עם מיקום שלילי:

SQL
SELECT title, price
FROM Paintings
WHERE likes > 3 * dislikes AND substr(title, -1, 1) = substr(painter, -1, 1);

בדיקה – על טבלת הדוגמה:

titlepainterlikes > 3·dislikes ?אות אחרונה זהה?נבחר?
SunsetMonet300 > 150 כןt = tכן
Blue SeaDali200 > 300 לאa ≠ iלא
GardenKlimt450 > 300 כןn ≠ tלא
Blue BallChagall90 > 120 לאl = lלא

השאילתה מחזירה שורה אחת – Sunset | 5000 – ולכן הפעולה תדפיס Number of paintings: 1. בטבלה מורחבת הוספנו את The Swan / Rubin עם 301 "אהבתי" ו־100 "לא אהבתי" – הוא הוחזר (301 > 300), ואילו ציור עם אותיות אחרונות שונות לא הוחזר גם כשהיו לו הרבה "אהבתי".

טעות נפוצה: להשתמש ב-LEFT במקום RIGHT, או לכתוב likes >= 3 * dislikes ("גדול מ..." הוא גדול ממש).

הקוד המלא
C#
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-

SELECT performer, price FROM Concerts WHERE city = 'Haifa' AND tickets >= 2000

4-

(1) "phone"
(2) x.length != 10
(3) x.charAt(1) != '5'
(4) x.charAt(i) < '0' || x.charAt(i) > '9'
(5) false

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-

public bool isStairs(int num) – אם num < 10 מחזירים false; שומרים את הספרה האחרונה ב-prev, ובלולאה משווים כל ספרה d ל-prev: אם d - prev != 1 && prev - d != 1 מחזירים false; בסוף true.

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)
{
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-

command.CommandText = "SELECT title, price FROM Paintings WHERE likes > 3 * dislikes AND RIGHT(title, 1) = RIGHT(painter, 1)"; (על טבלת הדוגמה יודפס Number of paintings: 1)

כל האתר במבט אחד

קיצורי דרך לכל הכלים, הבגרויות והקורסים

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