בעמוד הזה
SQL בסיסי: SELECT, WHERE לפי id וסינון פשוט
- לשלוף את כל השורות או עמודות נבחרות עם SELECT
- לשלוף רשומה אחת לפי id עם WHERE
- לכתוב תנאי סינון פשוטים עם =, <>, >, < ו-AND
- למיין תוצאות עם ORDER BY, ולהבין מה קורה כשלא נמצאה אף שורה
מה נלמד?
SELECT = ה-Read של CRUD: קריאת נתונים מטבלה.
- כל השורות:
SELECT * FROM students. - עמודות נבחרות:
SELECT name, email FROM students. - שורה אחת לפי id:
SELECT ... WHERE id = 2. - סינון פשוט עם
WHEREותנאים. - מיון עם
ORDER BY.
למה צריך את זה?
שתי השאילתות החשובות ביותר בכל API:
| Endpoint | SQL |
|---|---|
GET /students | SELECT ... FROM students |
GET /students/7 | SELECT ... FROM students WHERE id = 7 |
בכל פעם שאתם פותחים רשימה באפליקציה (מוצרים, הודעות, הזמנות) רצה מאחורי הקלעים שאילתת SELECT.
הסבר מהבסיס
SELECT … FROM
SELECT name, age FROM students;“בחר את העמודות name ו-age מתוך הטבלה students”. התוצאה היא טבלה חדשה (זמנית), עם השורות והעמודות שביקשתם. המסד לא משתנה: SELECT רק קורא, בדיוק כמו GET.
*(כוכבית) = כל העמודות.- הסדר ברשימה קובע את סדר העמודות בתוצאה.
WHERE — סינון שורות
SELECT name, age FROM students WHERE age > 23;WHERE = “רק השורות שעבורן התנאי נכון”. המסד בודק את התנאי על כל שורה, ומחזיר רק את המתאימות.
| אופרטור | משמעות | דוגמה |
|---|---|---|
= | שווה (סימן אחד!, לא ==) | WHERE id = 2 |
<> (או !=) | שונה | WHERE name <> 'Avi' |
> < >= <= | השוואה | WHERE age >= 18 |
AND | שני התנאים | WHERE age > 20 AND age < 30 |
OR | לפחות אחד | WHERE name = 'Dana' OR name = 'Noa' |
WHERE id — הכי חשוב
id הוא Primary Key, ייחודי, ולכן WHERE id = 2 מחזיר לכל היותר שורה אחת. זו השליפה של GET /students/{student_id}. והמסד מוצא אותה מהר מאוד, גם מתוך מיליוני שורות (כי Primary Key מאונדקס אוטומטית).
ORDER BY — מיון
SELECT name, age FROM students ORDER BY age;
SELECT name, age FROM students ORDER BY age DESC;ברירת המחדל היא סדר עולה (ASC). DESC = יורד. בלי ORDER BY, הסדר לא מובטח, ולכן אם הסדר חשוב, מבקשים אותו במפורש.
SELECT name, age FROM students = “תביאי לי את השם והגיל של כל הסטודנטים”. WHERE age > 23 = “רק מי שמעל 23”. ORDER BY age = “מסודרים לפי גיל”. WHERE id = 2 = “את התיק מספר 2”. את מה אתם אומרים, ואיך למצוא את זה זה כבר עניין שלה (SQL הצהרתי).
תחביר
SELECT * FROM table_name; -- all columns, all rows
SELECT col_a, col_b FROM table_name; -- chosen columns
SELECT col_a, col_b FROM table_name WHERE id = 3; -- one row by primary key
SELECT col_a FROM table_name WHERE col_b > 10 AND col_c = 'x';
SELECT col_a FROM table_name ORDER BY col_b DESC;-- בתחילת טקסט ב-SQL = הערה (כמו # ב-Python).
דוגמת קוד ראשונה
הטבלה מהשיעור הקודם:
id | name | age | email
---+------+-----+--------------
1 | Dana | 24 | dana@mail.com
2 | Avi | 31 | avi@mail.com
3 | Noa | 22 | noa@mail.comהריצו ב-Database Client (בקובץ .sql: מסמנים ← Run):
SELECT * FROM students;תוצאה:
id | name | age | email
1 | Dana | 24 | dana@mail.com
2 | Avi | 31 | avi@mail.com
3 | Noa | 22 | noa@mail.comSELECT name, email FROM students;name | email
Dana | dana@mail.com
Avi | avi@mail.com
Noa | noa@mail.comSELECT id, name, age, email FROM students WHERE id = 2;id | name | age | email
2 | Avi | 31 | avi@mail.comפירוק הקוד שורה אחר שורה
| שאילתה | מה המסד עשה |
|---|---|
SELECT * FROM students | כל העמודות, כל השורות. |
SELECT name, email FROM students | כל השורות, אבל רק שתי עמודות, בסדר שביקשנו. |
SELECT id, name, age, email ... WHERE id = 2 | עבר על השורות (בפועל, הלך ישר ל-id 2 בזכות ה-Primary Key), והחזיר רק את השורה שבה id = 2. |
שימו לב: בשאילתה השלישית כתבנו את רשימת העמודות במפורש, ולא *. זה ההרגל שנשתמש בו בקוד: אם בעתיד תתווסף לטבלה עמודה (אולי עם מידע רגיש, כמו סיסמה), היא לא “תזלוג” בטעות לתשובות של ה-API.
דוגמה נוספת
סינון, תנאים משולבים, מיון, ותוצאה ריקה.
SELECT name, age FROM students WHERE age > 23;name | age
Dana | 24
Avi | 31SELECT name, age FROM students WHERE age > 20 AND age < 30 ORDER BY age;name | age
Noa | 22
Dana | 24SELECT name FROM students ORDER BY name;name
Avi
Dana
NoaSELECT id, name FROM students WHERE id = 99;(no rows)פירוק:
age > 23— דנה (24) ואבי (31). נועה (22) לא עברה את התנאי.AND+ORDER BY— קודם סינון (רק בין 20 ל-30), ואז מיון של מה שנשאר. הסדר בשאילתה קבוע:SELECT ... FROM ... WHERE ... ORDER BY ....ORDER BY name— מיון אלפביתי של טקסט.WHERE id = 99— אין שורה כזו. זו לא שגיאה! התוצאה פשוט ריקה: 0 שורות. ב-Python,fetchone()יחזירNone(נושא מסדי נתונים ו-MySQL!), ו-fetchall()יחזיר רשימה ריקה. ב-API זה יהפוך ל-404.
טעות נפוצה
הטעות 1: == במקום =.
SELECT * FROM students WHERE id == 2;1064 (42000): You have an error in your SQL syntax; ... near '== 2' at line 1ב-SQL, השוואה היא = אחד. (וזה ההפך מ-Python, שבו = הוא השמה!)
הטעות 2: מחרוזת בלי גרש.
SELECT * FROM students WHERE name = Avi;1054 (42S22): Unknown column 'Avi' in 'where clause'בלי גרש, SQL חושב ש-Avi הוא שם של עמודה (בדיוק כמו print(Hello) בנושא מחשב, מערכת הפעלה ורשת). ← WHERE name = 'Avi'.
הטעות 3: סדר לא נכון של החלקים.
SELECT name FROM students ORDER BY age WHERE age > 20;1064 (42000): You have an error in your SQL syntax; ... near 'WHERE age > 20' at line 1הסדר: SELECT → FROM → WHERE → ORDER BY.
הטעות 4: להתייחס לתוצאה ריקה כשגיאה, או להפך. WHERE id = 99 שלא מצא כלום מחזיר 0 שורות, בלי Exception. הקוד שלנו הוא שצריך לבדוק (“לא נמצא”) ולהחזיר 404. אם לא בודקים, None[0] יקרוס.
הטעות 5: להניח שהשוואת טקסט רגישה לאותיות גדולות/קטנות. ב-MySQL, כברירת מחדל, WHERE name = 'avi' כן ימצא את Avi — ההשוואה לא מבחינה בין אותיות גדולות לקטנות. זה נוח לחיפוש, אבל יש לזה מחיר: עם UNIQUE על email, המסד יסרב לשמור את Dana@mail.com אם כבר קיים dana@mail.com. (וזה שונה מ-Python, שבו "avi" == "Avi" הוא False!)
תרגול
התרגילים מבוססים רק על מה שנלמד בשיעור הזה ובשיעורים שלפניו. נסו לבד, ורק אז פתחו את הפתרון.
תרגיל 1: SELECT בסיסי
בכל התרגילים בשיעור הזה, צרו קודם את הטבלה והנתונים:
import mysql.connector
connection = mysql.connector.connect(
host="localhost", user="root", password="kodkod", database="school")
cursor = connection.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL, age INT NOT NULL, city VARCHAR(50))""")
cursor.execute("""
INSERT INTO students (name, age, city) VALUES
('Dana', 24, 'Haifa'), ('Avi', 31, 'Tel Aviv'),
('Noa', 22, 'Haifa'), ('Tom', 28, NULL)""")
connection.commit()כתבו שאילתה שמחזירה את השם והגיל של כל הסטודנטים, והדפיסו כל שורה.
פלט צפוי:
('Dana', 24)
('Avi', 31)
('Noa', 22)
('Tom', 28)הצג פתרון
import mysql.connector
connection = mysql.connector.connect(
host="localhost", user="root", password="kodkod", database="school")
cursor = connection.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL, age INT NOT NULL, city VARCHAR(50))""")
cursor.execute("""
INSERT INTO students (name, age, city) VALUES
('Dana', 24, 'Haifa'), ('Avi', 31, 'Tel Aviv'),
('Noa', 22, 'Haifa'), ('Tom', 28, NULL)""")
connection.commit()
cursor.execute("SELECT name, age FROM students")
for row in cursor.fetchall():
print(row)
connection.close()('Dana', 24)
('Avi', 31)
('Noa', 22)
('Tom', 28)SELECT name, age — רק העמודות שצריך. SELECT * מחזיר את כולן.
תרגיל 2: WHERE לפי id
עם אותם נתונים, שלפו את הסטודנט ש-id שלו 2, ואת הסטודנט ש-id שלו 99.
פלט צפוי:
(2, 'Avi', 31, 'Tel Aviv')
Noneהצג פתרון
import mysql.connector
connection = mysql.connector.connect(
host="localhost", user="root", password="kodkod", database="school")
cursor = connection.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL, age INT NOT NULL, city VARCHAR(50))""")
cursor.execute("""
INSERT INTO students (name, age, city) VALUES
('Dana', 24, 'Haifa'), ('Avi', 31, 'Tel Aviv'),
('Noa', 22, 'Haifa'), ('Tom', 28, NULL)""")
connection.commit()
cursor.execute("SELECT * FROM students WHERE id = 2")
print(cursor.fetchone())
cursor.execute("SELECT * FROM students WHERE id = 99")
print(cursor.fetchone())
connection.close()(2, 'Avi', 31, 'Tel Aviv')
Noneתוצאה ריקה היא לא שגיאה: fetchone() מחזיר None כשאין שורה כזו.
תרגיל 3: סינון ומיון
עם אותם נתונים: שלפו את השמות של הסטודנטים מחיפה מתחת לגיל 30, ואת כל הסטודנטים ממוינים לפי גיל מהגדול לקטן.
פלט צפוי:
[('Dana',), ('Noa',)]
[('Avi', 31), ('Tom', 28), ('Dana', 24), ('Noa', 22)]הצג פתרון
import mysql.connector
connection = mysql.connector.connect(
host="localhost", user="root", password="kodkod", database="school")
cursor = connection.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL, age INT NOT NULL, city VARCHAR(50))""")
cursor.execute("""
INSERT INTO students (name, age, city) VALUES
('Dana', 24, 'Haifa'), ('Avi', 31, 'Tel Aviv'),
('Noa', 22, 'Haifa'), ('Tom', 28, NULL)""")
connection.commit()
cursor.execute("SELECT name FROM students WHERE city = 'Haifa' AND age < 30")
print(cursor.fetchall())
cursor.execute("SELECT name, age FROM students ORDER BY age DESC")
print(cursor.fetchall())
connection.close()[('Dana',), ('Noa',)]
[('Avi', 31), ('Tom', 28), ('Dana', 24), ('Noa', 22)]כל שורה היא tuple — גם כשיש עמודה אחת: ('Dana',).
תרגיל 4: NULL
עם אותם נתונים: מי הסטודנט שאין לו עיר? כתבו שתי שאילתות — אחת עם city = NULL ואחת עם city IS NULL — והסבירו את ההבדל.
פלט צפוי:
[]
[('Tom',)]הצג פתרון
import mysql.connector
connection = mysql.connector.connect(
host="localhost", user="root", password="kodkod", database="school")
cursor = connection.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL, age INT NOT NULL, city VARCHAR(50))""")
cursor.execute("""
INSERT INTO students (name, age, city) VALUES
('Dana', 24, 'Haifa'), ('Avi', 31, 'Tel Aviv'),
('Noa', 22, 'Haifa'), ('Tom', 28, NULL)""")
connection.commit()
cursor.execute("SELECT name FROM students WHERE city = NULL")
print(cursor.fetchall())
cursor.execute("SELECT name FROM students WHERE city IS NULL")
print(cursor.fetchall())
connection.close()[]
[('Tom',)]NULL פירושו “אין ערך”, ולכן city = NULL אף פעם לא נכון — אפילו לא עבור טום. בודקים ערך חסר רק עם IS NULL.
תרגיל 5: שאילתות על מוצרים
כתבו שאילתות SQL על טבלת products (name, price, stock), והריצו אותן ב-Database Client:
- שמות המוצרים שהמלאי שלהם מתחת ל-5.
- כל המוצרים ממוינים לפי המחיר, מהזול ליקר — שם ומחיר.
- כל המוצרים ממוינים לפי המחיר, מהיקר לזול.
הצג פתרון
SELECT name FROM products
WHERE stock < 5;
SELECT name, price FROM products
ORDER BY price;
SELECT name, price FROM products
ORDER BY price DESC;ORDER BYממיין מהקטן לגדול כברירת מחדל.DESCהופך את הסדר.
סיכום
SELECT cols FROM table— קריאה.*= כל העמודות, אבל בקוד עדיף לרשום אותן במפורש.WHERE condition— רק השורות שמתאימות.=(סימן אחד),<>,>,<,AND,OR. מחרוזות ב-'...'.WHERE id = 2— שורה אחת לכל היותר, לפי Primary Key. זהGET /students/{id}.ORDER BY col [DESC]— מיון. בלי ORDER BY הסדר לא מובטח.- סדר החלקים: SELECT → FROM → WHERE → ORDER BY.
- תוצאה ריקה אינה שגיאה. הקוד בודק אותה (
None/[]) ומחזיר 404. ל-NULL משתמשים ב-IS NULL.
דוקומנטציה רשמית
- MySQL — SELECT — שליפת נתונים
- MySQL Tutorial — Selecting Particular Rows — WHERE