מפתח
ברוכים הבאים!
פרויקט זה מיועד ללימוד שפת SQL למתחילים. הפרויקט כולל תיעוד מפורט בעברית ודוגמאות קוד מעשיות.
📋 תוכן עניינים
תיעוד (docs/)
- רקע והיסטוריה - מהו SQL ומאיפה הוא הגיע
- יסודות - מושגים בסיסיים שחייבים לדעת
- סינטקס וצורת כתיבה - איך כותבים שאילתות SQL
- סוגי נתונים - הטיפוסים הנפוצים ב-SQL
- שאילתות SELECT - קריאת נתונים מהטבלאות
- חיבורי טבלאות - JOIN וסוגיו השונים
- פונקציות צבירה - COUNT, SUM, AVG ועוד
- UPDATE ו-DELETE - עדכון ומחיקת נתונים
- טרנזקציות - ACID ועבודה בטוחה
- אינדקסים - שיפור ביצועים
- Views - תצוגות וירטואליות
דוגמאות קוד (examples/)
01-basics.sql- תחביר בסיסי והערות02-create.sql- יצירת מסדי נתונים וטבלאות03-insert.sql- הכנסת נתונים04-select.sql- שאילתות בסיסיות05-where.sql- סינון וחיפוש נתונים06-joins.sql- חיבור טבלאות07-aggregation.sql- פונקציות צבירה וקיבוץ08-subqueries.sql- שאילתות מקוננות09-update-delete.sql- עדכון ומחיקה10-transactions.sql- טרנזקציות11-indexes.sql- אינדקסים12-views.sql- תצוגות
🔧 דרישות מקדימות
לפני שמתחילים, מומלץ שיהיה מותקן אחד מהבאים:
💡 טיפ: למתחילים מומלץ להתחיל עם SQLite או להשתמש בסביבה אונליין כמו SQLite Online
🚀 התחלה מהירה
אפשרות 1: סביבה אונליין (מומלץ למתחילים)
פשוט גשו ל-SQLite Online והעתיקו את הדוגמאות מתיקיית examples/.
אפשרות 2: התקנה מקומית
- התקינו את אחד ממסדי הנתונים הנ"ל
- פתחו את הממשק שלו (MySQL Workbench, pgAdmin, וכו')
- הריצו את הקבצים מתיקיית
examples/
📚 סדר לימוד מומלץ
- התחילו מהרקע - הבינו מה זה SQL ולמה זה חשוב
- למדו את היסודות - טבלאות, עמודות, שורות ומפתחות
- הבינו את התחביר - כללי כתיבה נכונה
- תרגלו SELECT - קריאת נתונים היא הבסיס
- הוסיפו WHERE - למדו לסנן נתונים
- שלטו ב-JOIN - חיבור טבלאות הוא קריטי
- בנו שאילתות מורכבות - צברו ביטחון!
💡 טיפים למתחילים
טיפ 1: תמיד התחילו עם SELECT קטן לפני שאילתה גדולה
טיפ 2: השתמשו ב-LIMIT כדי לא להציף את עצמכם בתוצאות
טיפ 3: כתבו כל מילת מפתח בשורה נפרדת - זה קריא יותר
טיפ 4: שמרו על עקביות בסגנון הכתיבה שלכם
🔗 משאבים נוספים
- W3Schools SQL Tutorial
- SQLBolt - תרגול אינטראקטיבי
- LeetCode SQL - אתגרי SQL
בהצלחה בלימוד! 🎓
💻 מדריך מלא: פקודות טרמינל ל-MySQL
מדריך מקיף לעבודה עם MySQL דרך שורת הפקודה (Terminal/CMD), כולל Docker, התקנה מקומית ופקודות בסיסיות.
📌 תוכן עניינים
- התחברות ל-MySQL - סקירה כללית
- עבודה עם Docker
- עבודה עם MySQL מקומי
- פקודות MySQL בסיסיות
- פקודות מתקדמות
- טיפים ופתרון בעיות
🔌 שיטות התחברות ל-MySQL
ישנן שלוש דרכים עיקריות להתחבר ל-MySQL:
| שיטה | מתי להשתמש | יתרונות |
|---|---|---|
| Docker | סביבת פיתוח מבודדת | קל להתקנה, לא משבש את המערכת |
| התקנה מקומית | שימוש קבוע, פרודקשן | מהיר יותר, גישה ישירה |
| MySQL Workbench | ממשק גרפי | קל למתחילים, ויזואלי |
במדריך זה נתמקד בשורת הפקודה (Terminal/CMD).
🐳 עבודה עם Docker
למה Docker?
Docker מאפשר להריץ MySQL בסביבה מבודדת (Container) ללא התקנה מלאה על המחשב.
יתרונות: - התקנה מהירה - קל לנקות (מחיקת Container) - לא משפיע על המערכת - אותה סביבה בכל מחשב
התקנה ראשונית - פעם אחת בלבד!
שלב 1: התקנת Docker Desktop
Windows/Mac: 1. הורד מ-docker.com 2. התקן והפעל את Docker Desktop 3. וודא ש-Docker Desktop רץ (סמל לוויתן במגש המערכת)
Linux:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install docker.io
# התחל את Docker
sudo systemctl start docker
sudo systemctl enable docker
שלב 2: יצירת MySQL Container
פקודה ליצירת Container חדש:
docker run --name mysql-docker \
-e MYSQL_ROOT_PASSWORD=YourPassword123! \
-p 3306:3306 \
-d mysql:latest
הסבר על הפקודה:
| חלק | משמעות |
|---|---|
docker run |
יוצר ומריץ Container חדש |
--name mysql-docker |
שם ה-Container (תוכל לבחור כל שם) |
-e MYSQL_ROOT_PASSWORD=... |
הגדרת סיסמה למשתמש root |
-p 3306:3306 |
מיפוי פורט (3306 = פורט MySQL) |
-d |
הרצה ברקע (Detached mode) |
mysql:latest |
תמונת MySQL העדכנית ביותר |
שים לב: פקודה זו רק פעם אחת! ה-Container ייצור ויישאר קיים.
פקודות Docker יומיומיות
בדיקת סטטוס Containers
# הצגת Containers פעילים
docker ps
# הצגת כל ה-Containers (כולל כבויים)
docker ps -a
פלט לדוגמה:
CONTAINER ID IMAGE STATUS PORTS NAMES
abc123def456 mysql:latest Up 10 minutes 0.0.0.0:3306->3306/tcp mysql-docker
הסבר:
- STATUS: Up = Container פועל
- STATUS: Exited = Container כבוי
הפעלת Container
# הפעלת Container שכבוי
docker start mysql-docker
מתי להשתמש: - אחרי אתחול מחדש של המחשב - אחרי שעצרת את ה-Container
עצירת Container
# עצירת Container פעיל
docker stop mysql-docker
מתי להשתמש: - כשסיימת לעבוד - לפני כיבוי המחשב (אופציונלי)
כניסה ל-MySQL דרך Docker
הפקודה המלאה:
docker exec -it mysql-docker mysql -u root -p
הסבר:
- docker exec - הרץ פקודה בתוך Container פעיל
- -it - מצב אינטראקטיבי (Interactive Terminal)
- mysql-docker - שם ה-Container
- mysql - הפקודה להפעלת MySQL CLI
- -u root - התחבר כמשתמש root
- -p - תבקש סיסמה (תקליד בשורה הבאה)
אלטרנטיבה (עם הסיסמה בפקודה):
docker exec -it mysql-docker mysql -u root -pYourPassword123!
⚠️ אזהרה: הסיסמה תופיע בהיסטוריית הטרמינל!
צפייה ב-Logs
# הצגת לוגים של ה-Container
docker logs mysql-docker
# הצגת לוגים בזמן אמת
docker logs -f mysql-docker
שימושי לאיתור בעיות!
מחיקת Container (זהירות!)
# עצירה ומחיקה מלאה
docker stop mysql-docker
docker rm mysql-docker
⚠️ אזהרה: כל הנתונים ב-Container יימחקו!
לשמירת נתונים, השתמש ב-Volumes:
docker run --name mysql-docker \
-e MYSQL_ROOT_PASSWORD=YourPassword123! \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
-d mysql:latest
סדר פעולות מלא ב-Docker
תהליך עבודה יומיומי:
# 1. וודא ש-Docker Desktop פועל (Windows/Mac)
# 2. בדוק אם ה-Container קיים
docker ps -a
# 3. הפעל את ה-Container אם הוא כבוי
docker start mysql-docker
# 4. בדוק שהוא רץ
docker ps
# 5. התחבר ל-MySQL
docker exec -it mysql-docker mysql -u root -p
# הזן סיסמה: YourPassword123!
# 6. עבוד עם SQL
mysql> SHOW DATABASES;
mysql> USE my_database;
mysql> SELECT * FROM users;
# 7. צא מ-MySQL
mysql> EXIT;
# 8. (אופציונלי) עצור את ה-Container
docker stop mysql-docker
🖥️ עבודה עם MySQL מקומי
התקנה מקומית של MySQL
Windows
- הורד את MySQL Community Server:
- לך ל-dev.mysql.com/downloads
- בחר את הגרסה ל-Windows
-
הורד ה-Installer
-
התקן:
- הרץ את ה-Installer
- בחר "Developer Default" או "Server Only"
- הגדר סיסמה ל-root
-
השאר את כל ההגדרות כברירת מחדל
-
בדיקה:
mysql --version
macOS
דרך Homebrew (מומלץ):
# התקנת Homebrew (אם אין)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# התקנת MySQL
brew install mysql
# הפעלת MySQL
brew services start mysql
# הגדרת אבטחה ראשונית
mysql_secure_installation
Linux (Ubuntu/Debian)
# עדכון מאגר חבילות
sudo apt update
# התקנת MySQL Server
sudo apt install mysql-server
# הפעלת MySQL
sudo systemctl start mysql
sudo systemctl enable mysql
# הגדרת אבטחה
sudo mysql_secure_installation
התחברות ל-MySQL מקומי
פקודת התחברות בסיסית:
mysql -u root -p
הסבר:
- mysql - פקודת MySQL CLI
- -u root - שם משתמש (root = מנהל)
- -p - תבקש סיסמה
אחרי הזנת הסיסמה, תראה:
Welcome to the MySQL monitor.
mysql>
התחברות למסד נתונים ספציפי:
mysql -u root -p database_name
התחברות כמשתמש אחר:
mysql -u username -p
התחברות לשרת מרוחק:
mysql -h hostname -u username -p
# דוגמה:
mysql -h 192.168.1.100 -u admin -p
📂 פקודות MySQL בסיסיות
ניהול מסדי נתונים
הצגת כל מסדי הנתונים
SHOW DATABASES;
פלט לדוגמה:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| shop_db |
| test_db |
+--------------------+
יצירת מסד נתונים חדש
CREATE DATABASE my_database;
עם קידוד עברית:
CREATE DATABASE my_database
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
מחיקת מסד נתונים
DROP DATABASE my_database;
⚠️ אזהרה: פעולה בלתי הפיכה! כל הנתונים יימחקו.
גרסה בטוחה יותר:
DROP DATABASE IF EXISTS my_database;
בחירת מסד נתונים לעבודה
USE my_database;
פלט:
Database changed
מעתה, כל הפקודות יבוצעו על my_database
בדיקת מסד הנתונים הפעיל כרגע
SELECT DATABASE();
פלט:
+-------------+
| DATABASE() |
+-------------+
| my_database |
+-------------+
ניהול טבלאות
הצגת כל הטבלאות
SHOW TABLES;
פלט לדוגמה:
+----------------------+
| Tables_in_my_database|
+----------------------+
| users |
| products |
| orders |
+----------------------+
הצגת מבנה טבלה
DESCRIBE table_name;
או בקיצור:
DESC table_name;
פלט לדוגמה:
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| created_at | timestamp | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
הצגת פקודת CREATE של טבלה
SHOW CREATE TABLE table_name;
שימושי להעתקת מבנה טבלה!
הצגת עמודות בטבלה
SHOW COLUMNS FROM table_name;
זהה ל-DESCRIBE
יציאה מ-MySQL
EXIT;
או:
QUIT;
או: לחץ Ctrl + D (Linux/Mac) / Ctrl + Z ואז Enter (Windows)
🔧 פקודות מתקדמות
הצגת משתמשים
SELECT User, Host FROM mysql.user;
פלט לדוגמה:
+------------------+-----------+
| User | Host |
+------------------+-----------+
| root | localhost |
| app_user | localhost |
| readonly_user | % |
+------------------+-----------+
הצגת משתנה מערכת
SHOW VARIABLES LIKE 'variable_name';
דוגמאות:
-- הצגת גרסת MySQL
SELECT VERSION();
-- הצגת קידוד תווים
SHOW VARIABLES LIKE 'character_set%';
-- הצגת מיקום קבצי MySQL
SHOW VARIABLES LIKE 'datadir';
-- הצגת פורט
SHOW VARIABLES LIKE 'port';
הצגת פרוצסים פעילים
SHOW PROCESSLIST;
שימושי לאיתור שאילתות איטיות!
הצגת סטטוס MySQL
STATUS;
פלט לדוגמה:
--------------
mysql Ver 8.0.35 for Linux on x86_64
Connection id: 10
Current database: shop_db
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 8.0.35 MySQL Community Server
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
UNIX socket: /var/run/mysqld/mysqld.sock
Uptime: 2 hours 15 min 32 sec
--------------
הצגת אינדקסים
SHOW INDEX FROM table_name;
הצגת הרשאות משתמש
SHOW GRANTS FOR 'username'@'localhost';
דוגמה:
SHOW GRANTS FOR 'root'@'localhost';
ניקוי מסך
\c
או:
# מחוץ ל-MySQL (בטרמינל)
clear # Linux/Mac
cls # Windows
הרצת SQL מקובץ
מחוץ ל-MySQL:
mysql -u root -p database_name < file.sql
בתוך MySQL:
SOURCE /path/to/file.sql;
דוגמה:
SOURCE C:/backups/shop_db_backup.sql;
ייצוא תוצאות לקובץ
SELECT * FROM users
INTO OUTFILE '/tmp/users.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
⚠️ שים לב: דורש הרשאות FILE.
💡 טיפים ופתרון בעיות
קיצורי דרך שימושיים
| מקש | פעולה |
|---|---|
↑ / ↓ |
גלילה בהיסטוריית פקודות |
Tab |
השלמה אוטומטית של שמות |
Ctrl + L |
ניקוי מסך (Linux/Mac) |
Ctrl + C |
ביטול פקודה נוכחית |
Ctrl + D |
יציאה מ-MySQL (Linux/Mac) |
פתרון בעיות נפוצות
"Access denied for user 'root'@'localhost'"
פתרון 1: וודא שהסיסמה נכונה
mysql -u root -p
# הזן את הסיסמה בזהירות
פתרון 2: אפס סיסמה (Docker)
docker exec -it mysql-docker mysql --skip-password
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewPassword123!';
mysql> FLUSH PRIVILEGES;
"ERROR 2002: Can't connect to local MySQL server"
בדיקה 1: האם MySQL פועל?
# Docker
docker ps
# מקומי (Linux)
sudo systemctl status mysql
# מקומי (Mac)
brew services list
פתרון:
# Docker
docker start mysql-docker
# מקומי (Linux)
sudo systemctl start mysql
# מקומי (Mac)
brew services start mysql
"ERROR 1045: Access denied"
הסיבה: סיסמה שגויה או משתמש לא קיים.
פתרון:
# נסה עם משתמש אחר
mysql -u root -p
# בדוק משתמשים קיימים
SELECT User, Host FROM mysql.user;
"ERROR 1049: Unknown database"
הסיבה: מסד הנתונים לא קיים.
פתרון:
-- הצג מסדי נתונים קיימים
SHOW DATABASES;
-- צור מסד נתונים חדש
CREATE DATABASE my_database;
"ERROR 2003: Can't connect to MySQL server on 'localhost' (10061)"
הסיבה: MySQL לא פועל או לא מאזין על הפורט הנכון.
בדיקה:
# בדוק פורט (Windows)
netstat -ano | findstr :3306
# בדוק פורט (Linux/Mac)
netstat -tuln | grep 3306
טיפים לעבודה יעילה
1. שמירת היסטוריה
MySQL שומר היסטוריית פקודות ב:
- Linux/Mac: ~/.mysql_history
- Windows: %USERPROFILE%\.mysql_history
מחיקת היסטוריה (אבטחה):
rm ~/.mysql_history
2. קובץ תצורה אישי
צור קובץ: ~/.my.cnf (Linux/Mac) או my.ini (Windows)
[client]
user=root
password=YourPassword123!
host=localhost
כעת תוכל להתחבר ללא הזנת פרטים:
mysql
⚠️ אבטחה: הקובץ חייב להיות מוגן!
chmod 600 ~/.my.cnf
3. Aliases שימושיים
הוסף ל-.bashrc או .zshrc:
# התחברות מהירה
alias mysql-local='mysql -u root -p'
alias mysql-docker='docker exec -it mysql-docker mysql -u root -p'
# Docker shortcuts
alias mysql-start='docker start mysql-docker'
alias mysql-stop='docker stop mysql-docker'
alias mysql-logs='docker logs -f mysql-docker'
הפעל מחדש את הטרמינל או:
source ~/.bashrc
כעת:
mysql-start # הפעלת Docker
mysql-docker # כניסה ל-MySQL
4. שימוש ב-Pager
-- הפעלת pager (less)
pager less;
-- הצגת טבלה גדולה
SELECT * FROM large_table;
-- כיבוי pager
nopager;
5. פורמט פלט אנכי
-- הוסף \G בסוף השאילתה
SELECT * FROM users WHERE id = 1\G
פלט:
*************************** 1. row ***************************
id: 1
name: ישראל ישראלי
email: [email protected]
created_at: 2026-01-04 10:30:00
שימושי לשורות עם הרבה עמודות!
📝 סיכום פקודות מהירות
Docker
docker start mysql-docker # הפעלה
docker stop mysql-docker # עצירה
docker ps # בדיקת סטטוס
docker exec -it mysql-docker mysql -u root -p # כניסה
docker logs mysql-docker # צפייה בלוגים
MySQL מקומי
mysql -u root -p # התחברות
mysql -u root -p database_name # התחברות למסד ספציפי
mysql -h hostname -u username -p # חיבור מרוחק
בתוך MySQL
-- ניהול מסדי נתונים
SHOW DATABASES;
CREATE DATABASE db_name;
USE db_name;
DROP DATABASE db_name;
-- ניהול טבלאות
SHOW TABLES;
DESCRIBE table_name;
SHOW CREATE TABLE table_name;
-- מידע מערכת
SELECT VERSION();
SELECT DATABASE();
STATUS;
SHOW PROCESSLIST;
-- יציאה
EXIT;
🎯 תרגילים מעשיים
תרגיל 1: הקמת סביבת עבודה
# 1. הפעל MySQL (Docker או מקומי)
docker start mysql-docker
# 2. התחבר
docker exec -it mysql-docker mysql -u root -p
# 3. צור מסד נתונים
mysql> CREATE DATABASE practice_db;
# 4. עבור למסד
mysql> USE practice_db;
# 5. בדוק שאתה במסד הנכון
mysql> SELECT DATABASE();
# 6. צא
mysql> EXIT;
תרגיל 2: בדיקת מערכת
-- 1. גרסת MySQL
SELECT VERSION();
-- 2. משתמש נוכחי
SELECT USER();
-- 3. מסד נוכחי
SELECT DATABASE();
-- 4. זמן פעילות השרת
SHOW STATUS LIKE 'Uptime';
-- 5. קידוד תווים
SHOW VARIABLES LIKE 'character_set_database';
🔗 קישורים שימושיים
- תיעוד רשמי MySQL: dev.mysql.com/doc
- Docker Hub - MySQL: hub.docker.com/_/mysql
- MySQL Workbench: dev.mysql.com/downloads/workbench
📜 רקע והיסטוריה של SQL
מה זה SQL?
SQL (Structured Query Language - שפת שאילתות מובנית) היא שפת תכנות המיועדת לניהול ותשאול מסדי נתונים יחסיים.
-- example of a basic SQL query
SELECT name, age FROM users WHERE age > 18;
📅 ההיסטוריה של SQL
שנות ה-70: הלידה
- 1970 - אדגר קוד (Edgar F. Codd) מ-IBM מפרסם את המאמר המהפכני על מודל הנתונים היחסי
- 1974 - IBM מפתחת את SEQUEL (Structured English Query Language)
- 1979 - Oracle משחררת את הגרסה המסחרית הראשונה
שנות ה-80: התקינה
- 1986 - ANSI (American National Standards Institute) מאשרת את SQL כתקן
- 1987 - ISO מאשרת את SQL כתקן בינלאומי
ימינו
- SQL היא עדיין השפה הדומיננטית לעבודה עם מסדי נתונים יחסיים
- למעלה מ-90% מהארגונים משתמשים ב-SQL
🏢 מסדי נתונים פופולריים
| מסד נתונים | חברה | שימוש עיקרי |
|---|---|---|
| MySQL | Oracle | אתרי אינטרנט, סטארטאפים |
| PostgreSQL | קוד פתוח | יישומים מורכבים, GIS |
| SQL Server | Microsoft | ארגונים, .NET |
| SQLite | קוד פתוח | אפליקציות מובייל, פיתוח |
| Oracle DB | Oracle | ארגונים גדולים |
| MariaDB | קוד פתוח | תחליף ל-MySQL |
🔄 SQL לעומת NoSQL
SQL (מסדי נתונים יחסיים)
- ✅ מבנה קבוע (Schema)
- ✅ עקביות גבוהה (ACID)
- ✅ שפה סטנדרטית
- ✅ מתאים לנתונים מובנים
NoSQL (מסדי נתונים לא-יחסיים)
- ✅ גמישות במבנה
- ✅ ביצועים גבוהים בנתונים גדולים
- ✅ סקיילביליות אופקית
- ✅ מתאים לנתונים לא-מובנים
🎯 מתי להשתמש ב-SQL?
✅ כדאי להשתמש ב-SQL כאשר:
- יש קשרים ברורים בין הנתונים
- נדרשת עקביות גבוהה (בנקים, מסחר)
- המבנה של הנתונים ידוע מראש
- נדרשות שאילתות מורכבות
❌ אולי לשקול NoSQL כאשר:
- נתונים משתנים לעתים קרובות במבנה
- כמויות עצומות של נתונים (Big Data)
- נדרשת גמישות מקסימלית
💼 למה ללמוד SQL?
- דרישה גבוהה בשוק העבודה - כמעט כל תפקיד טכני דורש SQL
- שפה אוניברסלית - עובדת על רוב מסדי הנתונים
- קל ללמוד - תחביר קריא ואינטואיטיבי
- כוח רב - גישה לנתונים בשניות
- יציבות - SQL כאן כבר 50+ שנה ולא הולכת לשום מקום
🔑 מושגי מפתח
| מונח | הסבר |
|---|---|
| Database | מסד נתונים - אוסף של טבלאות |
| Table | טבלה - אוסף של שורות |
| Row/Record | שורה/רשומה - פריט נתונים בודד |
| Column/Field | עמודה/שדה - תכונה של הנתונים |
| Query | שאילתה - בקשה למסד הנתונים |
| Schema | סכמה - מבנה מסד הנתונים |
🏗️ יסודות SQL
מבנה מסד נתונים יחסי
מסד נתונים יחסי מורכב מטבלאות המקושרות זו לזו באמצעות מפתחות.
┌─────────────────────────────────────────────────────────┐
│ מסד נתונים (Database) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ users │ │ orders │ │ products │ │
│ │ (טבלה) │ │ (טבלה) │ │ (טבלה) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────┘
📊 מבנה טבלה
טבלה מורכבת מעמודות (שדות) ושורות (רשומות):
טבלת users (משתמשים):
┌────┬─────────┬─────────────────────┬─────┐
│ id │ name │ email │ age │ ← עמודות (Columns)
├────┼─────────┼─────────────────────┼─────┤
│ 1 │ יוסי │ [email protected] │ 25 │ ← שורה (Row)
│ 2 │ שרה │ [email protected] │ 30 │ ← שורה (Row)
│ 3 │ דוד │ [email protected] │ 28 │ ← שורה (Row)
└────┴─────────┴─────────────────────┴─────┘
מאפייני עמודות
- שם - שם ייחודי לזיהוי העמודה
- סוג נתונים - מספר, טקסט, תאריך וכו'
- אילוצים - האם חובה, ייחודי וכו'
🔑 מפתחות (Keys)
מפתח ראשי (Primary Key)
- מזהה ייחודי לכל שורה בטבלה
- לא יכול להיות ריק (NULL)
- לרוב מספר שעולה אוטומטית (AUTO_INCREMENT)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT, -- מפתח ראשי
name VARCHAR(100),
email VARCHAR(255)
);
מפתח זר (Foreign Key)
- מקשר בין טבלאות
- מפנה למפתח ראשי בטבלה אחרת
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT, -- מפתח זר
total DECIMAL(10,2),
FOREIGN KEY (user_id) REFERENCES users(id)
);
🔗 סוגי קשרים בין טבלאות
קשר One-to-One (1:1)
שורה אחת בטבלה A מתאימה לשורה אחת בלבד בטבלה B.
users profiles
┌────┐ ┌────┐
│ 1 │────────▶│ 1 │
│ 2 │────────▶│ 2 │
│ 3 │────────▶│ 3 │
└────┘ └────┘
דוגמה: משתמש ← פרופיל
קשר One-to-Many (1:N)
שורה אחת בטבלה A יכולה להתאים למספר שורות בטבלה B.
users orders
┌────┐ ┌────┐
│ 1 │────┬───▶│ 1 │
│ │ └───▶│ 2 │
│ 2 │────────▶│ 3 │
│ 3 │ ┌───▶│ 4 │
│ │────┴───▶│ 5 │
└────┘ └────┘
דוגמה: משתמש אחד ← הזמנות רבות
קשר Many-to-Many (N:N)
שורות רבות בטבלה A יכולות להתאים לשורות רבות בטבלה B.
students enrollments courses
┌────┐ ┌────┬────┐ ┌────┐
│ 1 │◀───────▶│ 1 │ 1 │◀────▶│ 1 │
│ 2 │◀───────▶│ 1 │ 2 │◀────▶│ 2 │
│ 3 │◀───────▶│ 2 │ 2 │◀────▶│ 3 │
└────┘ │ 3 │ 1 │ └────┘
└────┴────┘
(טבלת קשר)
דוגמה: סטודנטים ← קורסים (דרך טבלת הרשמות)
📝 סוגי פעולות SQL
DDL - Data Definition Language
פקודות להגדרת מבנה מסד הנתונים:
| פקודה | תיאור |
|---|---|
CREATE |
יצירת טבלה/מסד נתונים |
ALTER |
שינוי מבנה טבלה |
DROP |
מחיקת טבלה/מסד נתונים |
TRUNCATE |
ריקון טבלה |
DML - Data Manipulation Language
פקודות לעבודה עם הנתונים:
0
| פקודה | תיאור |
|-------|--------|
| SELECT | קריאת נתונים |
| INSERT | הוספת נתונים |
| UPDATE | עדכון נתונים |
| DELETE | מחיקת נתונים |
DCL - Data Control Language
פקודות להרשאות:
| פקודה | תיאור |
|---|---|
GRANT |
הענקת הרשאות |
REVOKE |
שלילת הרשאות |
⚠️ אילוצים (Constraints)
אילוצים מגדירים כללים לנתונים בטבלה:
| אילוץ | הסבר |
|---|---|
PRIMARY KEY |
מפתח ראשי - ייחודי ולא ריק |
SERIAL |
מפתח ראשי - ייחודי ולא ריק |
FOREIGN KEY |
מפתח זר - קשר לטבלה אחרת |
UNIQUE |
ערכים ייחודיים בלבד |
NOT NULL |
לא מאפשר ערך ריק |
DEFAULT |
ערך ברירת מחדל |
CHECK |
תנאי לערכים מותרים |
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) CHECK (price > 0),
category VARCHAR(50) DEFAULT 'general',
sku VARCHAR(20) UNIQUE
);
🎯 סיכום
- מסד נתונים יחסי = אוסף של טבלאות מקושרות
- טבלה = עמודות (שדות) + שורות (רשומות)
- מפתח ראשי = מזהה ייחודי
- מפתח זר = קישור בין טבלאות
- אילוצים = כללים לשמירה על תקינות הנתונים
✍️ סינטקס וצורת כתיבה ב-SQL
כללי תחביר בסיסיים
1. מילות מפתח (Keywords)
מילות מפתח ב-SQL הן לא רגישות לאותיות (case-insensitive):
-- All אלה עובדים:
SELECT * FROM users;
select * from users;
Select * From Users;
-- ✅ מומלץ: מילות מפתח באותיות גדולות
SELECT * FROM users;
2. סיום פקודה
כל פקודה מסתיימת בנקודה-פסיק (;):
SELECT * FROM users;
SELECT * FROM orders;
3. רווחים ושורות חדשות
SQL מתעלם מרווחים ושורות חדשות:
-- All אלה זהים:
SELECT name, age FROM users WHERE age > 18;
SELECT name, age
FROM users
WHERE age > 18;
SELECT
name,
age
FROM
users
WHERE
age > 18;
📐 סגנון כתיבה מומלץ
מבנה בסיסי של שאילתה
SELECT
column1,
column2,
column3
FROM
table_name
WHERE
condition
ORDER BY
column1;
דוגמה מעשית
-- ❌ Not recommended - קשה לקריאה
SELECT id,name,email,age FROM users WHERE age>18 AND status='active' ORDER BY name;
-- ✅ מומלץ - קריא וברור
SELECT
id,
name,
email,
age
FROM
users
WHERE
age > 18
AND status = 'active'
ORDER BY
name;
💬 הערות בקוד
הערת שורה בודדת
-- This הערה
SELECT * FROM users; -- הערה בסוף שורה
הערת בלוק (מרובת שורות)
/*
this
זוהי הערה
שמשתרעת על
מספר שורות
*/
SELECT * FROM users;
דוגמה מעשית
-- ============================================
-- Query: משתמשים פעילים מעל גיל 18
-- מחבר: צוות פיתוח
-- תאריך: 2024-01-01
-- ============================================
SELECT
id,
name,
email
FROM
users
WHERE
age >= 18 -- רק בגירים
AND status = 'active' -- רק פעילים
ORDER BY
created_at DESC; -- מהחדש לישן
🔤 מחרוזות וערכים
מחרוזות (Strings)
מחרוזות מוקפות בגרשיים בודדות:
-- ✅ Right
SELECT * FROM users WHERE name = 'יוסי';
-- ❌ לא בכל מסדי נתונים
SELECT * FROM users WHERE name = "יוסי";
מספרים
מספרים ללא גרשיים:
SELECT * FROM users WHERE age = 25;
SELECT * FROM products WHERE price = 99.99;
ערכי NULL
NULL מייצג ערך חסר (לא אפס, לא ריק):
-- NULL check
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;
-- ❌ לא עובד!
SELECT * FROM users WHERE phone = NULL;
🏷️ שמות ומזהים
כללי שמות טבלאות ועמודות
-- ✅ Recommended: snake_case
user_profiles
order_items
created_at
-- ✅ גם טוב: camelCase
userProfiles
orderItems
createdAt
-- ❌ נמנעים: רווחים ותווים מיוחדים
"user profiles" -- דורש גרשיים
user-profiles -- בעייתי
שימוש בגרשיים לשמות מיוחדים
-- MySQL: backticks
SELECT `order` FROM `users`;
-- PostgreSQL/SQL Server: מרכאות כפולות
SELECT "order" FROM "users";
-- SQL Server: סוגריים מרובעים
SELECT [order] FROM [users];
🎭 כינויים (Aliases)
כינוי לעמודה
SELECT
name AS שם,
age AS גיל,
email AS "כתובת מייל" -- עם רווחים צריך גרשיים
FROM
users;
כינוי לטבלה
SELECT
u.name,
o.total
FROM
users AS u
JOIN orders AS o ON u.id = o.user_id;
-- AS אופציונלי:
SELECT
u.name,
o.total
FROM
users u
JOIN orders o ON u.id = o.user_id;
📋 סדר הפקודות בשאילתה
שאילתת SELECT חייבת לעמוד בסדר הבא:
SELECT -- 1. מה לבחור (עמודות)
FROM -- 2. מאיפה (טבלאות)
JOIN -- 3. חיבור טבלאות (אופציונלי)
WHERE -- 4. תנאים לסינון שורות
GROUP BY -- 5. קיבוץ (אופציונלי)
HAVING -- 6. תנאים על קבוצות (אופציונלי)
ORDER BY -- 7. מיון (אופציונלי)
LIMIT -- 8. הגבלת תוצאות (אופציונלי)
דוגמה מלאה
SELECT
category,
COUNT(*) AS count,
AVG(price) AS avg_price
FROM
products
JOIN
categories ON products.category_id = categories.id
WHERE
price > 0
GROUP BY
category
HAVING
COUNT(*) >= 5
ORDER BY
avg_price DESC
LIMIT 10;
⚡ טיפים לכתיבה נקייה
- עקביות - בחרו סגנון ושמרו עליו
- הזחה - השתמשו ב-4 רווחים או TAB
- שורות - פקודה חדשה = שורה חדשה
- הערות - הסבירו את הלוגיקה, לא את הקוד
- שמות משמעותיים -
user_idעדיף עלuid
📦 סוגי נתונים ב-SQL
סקירה כללית
SQL תומך במגוון סוגי נתונים המחולקים לקטגוריות עיקריות:
| קטגוריה | דוגמאות |
|---|---|
| מספרים | INT, DECIMAL, FLOAT |
| טקסט | VARCHAR, TEXT, CHAR |
| תאריכים | DATE, DATETIME, TIMESTAMP |
| בוליאני | BOOLEAN, BIT |
| בינארי | BLOB, BINARY |
🔢 סוגי נתונים מספריים
מספרים שלמים
| טיפוס | טווח | שימוש |
|---|---|---|
TINYINT |
-128 עד 127 | גילאים, דגלים קטנים |
SMALLINT |
-32,768 עד 32,767 | מספרים קטנים |
INT / INTEGER |
±2 מיליארד | שימוש כללי |
BIGINT |
±9 קווינטיליון | מזהים ייחודיים גדולים |
CREATE TABLE users (
id INT, -- מזהה רגיל
age TINYINT, -- גיל (0-127 מספיק)
views BIGINT, -- צפיות (יכול להיות מספר עצום)
followers INT UNSIGNED -- לא שלילי (0 עד 4 מיליארד)
);
מספרים עשרוניים
| טיפוס | דיוק | שימוש |
|---|---|---|
DECIMAL(p,s) / NUMERIC |
מדויק | כסף, מדידות מדויקות |
FLOAT |
משוער | מדע, חישובים |
DOUBLE |
משוער (כפול) | חישובים מדעיים |
CREATE TABLE products (
price DECIMAL(10, 2), -- עד 99,999,999.99
tax_rate DECIMAL(5, 4), -- עד 9.9999 (אחוזים)
weight FLOAT -- משקל (לא צריך דיוק מלא)
);
⚠️ חשוב: לכסף תמיד השתמשו ב-
DECIMAL, לא ב-FLOAT!
📝 סוגי נתונים טקסטואליים
טקסט באורך קבוע/משתנה
| טיפוס | אורך | שימוש |
|---|---|---|
CHAR(n) |
קבוע (n תווים תמיד) | קודי מדינה, מס' זהות |
VARCHAR(n) |
משתנה (עד n תווים) | שמות, כתובות |
TEXT |
ארוך מאוד | תיאורים, מאמרים |
CREATE TABLE users (
country_code CHAR(2), -- 'IL', 'US'
name VARCHAR(100), -- שם באורך משתנה
email VARCHAR(255), -- מייל
bio TEXT -- ביוגרפיה ארוכה
);
הבדלים בין מסדי נתונים
-- MySQL
CREATE TABLE articles (body LONGTEXT);
-- PostgreSQL
CREATE TABLE articles (body TEXT);
-- SQL Server
CREATE TABLE articles (body NVARCHAR(MAX));
📅 סוגי נתונים לתאריכים
| טיפוס | פורמט | דוגמה |
|---|---|---|
DATE |
תאריך בלבד | '2024-01-15' |
TIME |
שעה בלבד | '14:30:00' |
DATETIME |
תאריך + שעה | '2024-01-15 14:30:00' |
TIMESTAMP |
תאריך + שעה (UTC) | '2024-01-15 12:30:00' |
YEAR |
שנה בלבד | 2024 |
CREATE TABLE events (
event_date DATE, -- תאריך האירוע
start_time TIME, -- שעת התחלה
created_at DATETIME, -- מתי נוצר
updated_at TIMESTAMP -- עדכון אוטומטי
);
-- הכנסת נתונים
INSERT INTO events (event_date, start_time, created_at)
VALUES ('2024-06-15', '18:00:00', NOW());
✓ סוג נתונים בוליאני
-- MySQL
CREATE TABLE users (
is_active BOOLEAN, -- TRUE/FALSE או 1/0
is_admin TINYINT(1) -- אלטרנטיבה נפוצה
);
-- PostgreSQL
CREATE TABLE users (
is_active BOOLEAN
);
-- SQL Server
CREATE TABLE users (
is_active BIT -- 0 או 1
);
-- שימוש
INSERT INTO users (is_active) VALUES (TRUE);
INSERT INTO users (is_active) VALUES (1);
INSERT INTO users (is_active) VALUES (FALSE);
🎨 סוגי נתונים מיוחדים
JSON
-- MySQL 5.7+
CREATE TABLE settings (
data JSON
);
INSERT INTO settings (data)
VALUES ('{"theme": "dark", "language": "he"}');
-- שליפה
SELECT data->'$.theme' FROM settings;
ENUM (רשימת ערכים מוגדרת)
CREATE TABLE orders (
status ENUM('pending', 'paid', 'shipped', 'delivered')
);
INSERT INTO orders (status) VALUES ('pending');
UUID
-- PostgreSQL
CREATE TABLE users (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY
);
-- MySQL
CREATE TABLE users (
id CHAR(36) PRIMARY KEY
);
INSERT INTO users (id) VALUES (UUID());
📊 טבלת השוואה מהירה
| צורך | טיפוס מומלץ |
|---|---|
| מזהה (ID) | INT AUTO_INCREMENT או BIGINT |
| כסף/מחיר | DECIMAL(10,2) |
| שם משתמש | VARCHAR(50) |
| אימייל | VARCHAR(255) |
| סיסמה (מוצפנת) | VARCHAR(255) |
| טקסט ארוך | TEXT |
| גיל | TINYINT UNSIGNED |
| דגל כן/לא | BOOLEAN או TINYINT(1) |
| תאריך לידה | DATE |
| זמן יצירה | TIMESTAMP |
| קואורדינטות | DECIMAL(9,6) |
⚡ טיפים
- בחרו את הסוג הקטן ביותר שמספיק לצרכים שלכם
- לכסף: DECIMAL - לעולם לא FLOAT
- לטקסט: VARCHAR - אלא אם צריך TEXT
- למפתחות: INT - אלא אם צריך BIGINT
- זכרו - סוגי נתונים משפיעים על ביצועים!
🔍 שאילתות SELECT ב-SQL
מבנה בסיסי
SELECT column1, column2
FROM table_name
WHERE condition;
📌 SELECT בסיסי
בחירת כל העמודות
-- The asterisk (*) represents "all"
SELECT * FROM users;
בחירת עמודות ספציפיות
SELECT name, email, age
FROM users;
בחירת עמודות עם כינוי
SELECT
name AS שם,
email AS "כתובת מייל",
age AS גיל
FROM users;
🎯 WHERE - סינון תוצאות
אופרטורי השוואה
| אופרטור | משמעות | דוגמה |
|---|---|---|
= |
שווה | age = 25 |
<> או != |
שונה | status <> 'inactive' |
> |
גדול מ | price > 100 |
< |
קטן מ | age < 18 |
>= |
גדול או שווה | age >= 18 |
<= |
קטן או שווה | price <= 50 |
-- Users over 18 years old
SELECT * FROM users WHERE age > 18;
-- Products with a specific price
SELECT * FROM products WHERE price = 99.99;
אופרטורים לוגיים
-- AND - שני התנאים חייבים להתקיים
SELECT * FROM users
WHERE age >= 18 AND status = 'active';
-- OR - לפחות תנאי אחד
SELECT * FROM users
WHERE role = 'admin' OR role = 'moderator';
-- NOT - היפוך התנאי
SELECT * FROM users
WHERE NOT status = 'banned';
-- שילוב עם סוגריים
SELECT * FROM products
WHERE (category = 'electronics' OR category = 'computers')
AND price < 1000;
🔎 אופרטורים מיוחדים
BETWEEN - טווח ערכים
-- Ages between 18 and 30 (inclusive)
SELECT * FROM users
WHERE age BETWEEN 18 AND 30;
-- Prices in a range
SELECT * FROM products
WHERE price BETWEEN 100 AND 500;
-- תאריכים
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
IN - רשימת ערכים
-- Instead of multiple OR
SELECT * FROM users
WHERE country IN ('Israel', 'USA', 'UK');
-- Equivelent to:
SELECT * FROM users
WHERE country = 'Israel'
OR country = 'USA'
OR country = 'UK';
LIKE - חיפוש תבניות
| תבנית | משמעות |
|---|---|
% |
אפס או יותר תווים |
_ |
תו בודד בדיוק |
-- Names starting with "יו"
SELECT * FROM users WHERE name LIKE 'יו%';
-- Emails ending with "gmail.com"
SELECT * FROM users WHERE email LIKE '%@gmail.com';
-- שמות עם בדיוק 4 אותיות
SELECT * FROM users WHERE name LIKE '____';
-- מכיל את המילה "ספר"
SELECT * FROM products WHERE description LIKE '%ספר%';
IS NULL / IS NOT NULL
-- Users without a phone number
SELECT * FROM users WHERE phone IS NULL;
-- Users with a phone number
SELECT * FROM users WHERE phone IS NOT NULL;
📊 ORDER BY - מיון
-- Ascending order (default) מיון עולה
SELECT * FROM products ORDER BY price;
SELECT * FROM products ORDER BY price ASC;
-- Descending order מיון יורד
SELECT * FROM products ORDER BY price DESC;
-- מיון לפי מספר עמודות
SELECT * FROM products
ORDER BY category ASC, price DESC;
-- מיון לפי עמודה לא בסלקט
SELECT name, age FROM users
ORDER BY created_at DESC;
📉 LIMIT - הגבלת תוצאות
-- Ten התוצאות הראשונות
SELECT * FROM products LIMIT 10;
-- 10 המוצרים היקרים ביותר
SELECT * FROM products
ORDER BY price DESC
LIMIT 10;
-- דילוג על תוצאות (לפאגינציה)
-- MySQL/PostgreSQL
SELECT * FROM products LIMIT 10 OFFSET 20;
-- SQL Server
SELECT * FROM products
ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
⭐ DISTINCT - ערכים ייחודיים
-- All כל הקטגוריות (ללא כפילויות)
SELECT DISTINCT category FROM products;
-- שילוב עמודות
SELECT DISTINCT city, country FROM users;
-- ספירת ערכים ייחודיים
SELECT COUNT(DISTINCT category) FROM products;
🧮 ביטויים וחישובים
-- Basic Expressions חישובים בסיסיים
SELECT
name,
price,
quantity,
price * quantity AS total
FROM order_items;
-- פונקציות מחרוזת
SELECT
CONCAT(first_name, ' ', last_name) AS full_name,
UPPER(email) AS email_caps,
LENGTH(name) AS name_length
FROM users;
-- עיגול מספרים
SELECT
price,
ROUND(price, 0) AS rounded_price,
FLOOR(price) AS floor_price,
CEIL(price) AS ceil_price
FROM products;
📋 דוגמה מקיפה
-- Find את 10 המשתמשים הפעילים מישראל
-- שנרשמו ב-2024, מסודרים לפי תאריך הרשמה
SELECT
id,
name AS שם,
email AS מייל,
created_at AS "תאריך הרשמה"
FROM
users
WHERE
country = 'Israel'
AND status = 'active'
AND created_at BETWEEN '2024-01-01' AND '2024-12-31'
ORDER BY
created_at DESC
LIMIT 10;
💡 טיפים
- **הימנעו מ-SELECT *** - ציינו עמודות ספציפיות
- השתמשו ב-LIMIT - במיוחד בפיתוח
- בדקו NULL עם IS NULL, לא עם =
- סדר הפקודות - SELECT, FROM, WHERE, ORDER BY, LIMIT
🔗 חיבורי טבלאות (JOIN)
למה צריך JOIN?
במסד נתונים יחסי, הנתונים מפוזרים בטבלאות נפרדות. JOIN מאפשר לחבר אותם יחד.
🎯 סוגי JOIN
| סוג | מה מחזיר |
|---|---|
INNER JOIN |
רק התאמות בשתי הטבלאות |
LEFT JOIN |
הכל משמאל + התאמות מימין |
RIGHT JOIN |
הכל מימין + התאמות משמאל |
FULL JOIN |
הכל משתי הטבלאות |
CROSS JOIN |
כל השילובים האפשריים |
1️⃣ INNER JOIN
SELECT users.name, orders.total
FROM users
INNER JOIN orders ON users.id = orders.user_id;
2️⃣ LEFT JOIN
SELECT users.name, orders.total
FROM users
LEFT JOIN orders ON users.id = orders.user_id;
3️⃣ חיבור מספר טבלאות
SELECT o.id, u.name, p.name AS product
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id;
📊 פונקציות צבירה (Aggregation)
פונקציות צבירה בסיסיות
| פונקציה | תיאור |
|---|---|
COUNT() |
ספירת שורות |
SUM() |
סכום ערכים |
AVG() |
ממוצע |
MIN() |
ערך מינימלי |
MAX() |
ערך מקסימלי |
SELECT
COUNT(*) AS total_users,
AVG(age) AS average_age,
MIN(age) AS youngest,
MAX(age) AS oldest
FROM users;
🎯 GROUP BY
קיבוץ לפי עמודה:
SELECT category, COUNT(*) AS count
FROM products
GROUP BY category;
🔍 HAVING
תנאי על קבוצות (בניגוד ל-WHERE שעל שורות):
SELECT category, COUNT(*) AS count
FROM products
GROUP BY category
HAVING COUNT(*) >= 5;
✏️ UPDATE ו-DELETE - עדכון ומחיקת נתונים
UPDATE - עדכון נתונים
תחביר בסיסי
UPDATE table_name
SET column1 = value1, column2 = value2
WHERE condition;
⚠️ זהירות: תמיד השתמשו ב-WHERE! בלעדיו תעדכנו את כל הטבלה!
דוגמאות UPDATE
-- עדכון שדה בודד
UPDATE users
SET status = 'active'
WHERE id = 5;
-- עדכון מספר שדות
UPDATE products
SET price = 99.99, stock = 50
WHERE id = 10;
-- עדכון עם חישוב
UPDATE products
SET price = price * 1.10 -- העלאה של 10%
WHERE category = 'electronics';
-- עדכון לפי תנאי מורכב
UPDATE orders
SET status = 'cancelled'
WHERE status = 'pending'
AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY);
UPDATE עם JOIN
-- עדכון לפי נתונים מטבלה אחרת
UPDATE orders o
JOIN users u ON o.user_id = u.id
SET o.discount = 10
WHERE u.membership = 'premium';
DELETE - מחיקת נתונים
תחביר בסיסי
DELETE FROM table_name
WHERE condition;
⚠️ זהירות: תמיד השתמשו ב-WHERE! בלעדיו תמחקו את כל הטבלה!
דוגמאות DELETE
-- מחיקת שורה בודדת
DELETE FROM users WHERE id = 5;
-- מחיקת לפי תנאי
DELETE FROM orders
WHERE status = 'cancelled';
-- מחיקת עם LIMIT
DELETE FROM logs
WHERE created_at < '2023-01-01'
LIMIT 1000;
TRUNCATE vs DELETE
| פקודה | מה עושה | מהירות | ניתן לבטל? |
|---|---|---|---|
DELETE FROM table |
מוחק שורות אחת אחת | איטי | כן |
TRUNCATE TABLE table |
מאפס את כל הטבלה | מהיר | לא |
-- מחיקת כל השורות (איטי, עם לוג)
DELETE FROM logs;
-- איפוס הטבלה (מהיר, ללא לוג)
TRUNCATE TABLE logs;
🛡️ טיפים לבטיחות
-
תמיד SELECT לפני UPDATE/DELETE
-- קודם בדקו מה ייפגע SELECT * FROM users WHERE status = 'inactive'; -- ואז עדכנו/מחקו DELETE FROM users WHERE status = 'inactive'; -
השתמשו ב-LIMIT
DELETE FROM logs WHERE year < 2020 LIMIT 100; -
עבדו בטרנזקציה
START TRANSACTION; DELETE FROM users WHERE id = 5; -- בדקו שהכל בסדר, ואז: COMMIT; -- או ROLLBACK לביטול
🔄 טרנזקציות (Transactions)
מה זה טרנזקציה?
טרנזקציה היא קבוצת פעולות שמתבצעות יחד - או שכולן מצליחות, או שאף אחת לא מתבצעת.
עקרונות ACID
| עיקרון | הסבר |
|---|---|
| Atomicity | אטומיות - הכל או כלום |
| Consistency | עקביות - המערכת תמיד במצב תקין |
| Isolation | בידוד - טרנזקציות לא מפריעות זו לזו |
| Durability | עמידות - שינויים נשמרים לצמיתות |
תחביר בסיסי
-- התחלת טרנזקציה
START TRANSACTION;
-- או
BEGIN;
-- ביצוע פעולות
INSERT INTO ...
UPDATE ...
DELETE ...
-- אישור - שמירת השינויים
COMMIT;
-- או ביטול - החזרת המצב
ROLLBACK;
דוגמה: העברת כסף
-- העברת 100₪ מחשבון A לחשבון B
START TRANSACTION;
-- הורדה מחשבון A
UPDATE accounts
SET balance = balance - 100
WHERE id = 'A';
-- הוספה לחשבון B
UPDATE accounts
SET balance = balance + 100
WHERE id = 'B';
-- אם הכל הצליח - אישור
COMMIT;
מה קורה אם יש שגיאה?
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 'A';
-- שגיאה! חשבון B לא קיים
UPDATE accounts SET balance = balance + 100 WHERE id = 'B'; -- נכשל
-- ביטול - הכסף חוזר לחשבון A
ROLLBACK;
SAVEPOINT - נקודות שמירה
START TRANSACTION;
INSERT INTO orders (user_id, total) VALUES (1, 100);
SAVEPOINT order_created;
INSERT INTO order_items (...) VALUES (...);
-- שגיאה בפריט
ROLLBACK TO order_created; -- חוזרים רק עד הנקודה
-- ההזמנה עדיין קיימת
COMMIT;
רמות בידוד (Isolation Levels)
-- הגדרת רמת בידוד
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
-- רמות זמינות:
-- READ UNCOMMITTED - הכי מהיר, הכי פחות בטוח
-- READ COMMITTED - ברירת מחדל ברוב מסדי הנתונים
-- REPEATABLE READ - קריאות חוזרות נותנות אותו תוצאה
-- SERIALIZABLE - הכי בטוח, הכי איטי
AUTO COMMIT
-- MySQL: כברירת מחדל כל פקודה היא טרנזקציה נפרדת
SET autocommit = 0; -- כיבוי
SET autocommit = 1; -- הפעלה
⚡ אינדקסים (Indexes)
מה זה אינדקס?
אינדקס הוא מבנה נתונים שמאיץ חיפושים בטבלה, בדומה לאינדקס בספר.
ללא אינדקס: סורק את כל הטבלה (100,000 שורות)
עם אינדקס: קפיצה ישירה לנתונים הרלוונטיים
יצירת אינדקס
-- אינדקס בסיסי
CREATE INDEX idx_email ON users(email);
-- אינדקס ייחודי
CREATE UNIQUE INDEX idx_username ON users(username);
-- אינדקס על מספר עמודות
CREATE INDEX idx_name_age ON users(name, age);
סוגי אינדקסים
| סוג | שימוש |
|---|---|
INDEX |
אינדקס רגיל |
UNIQUE INDEX |
ערכים ייחודיים |
PRIMARY KEY |
מפתח ראשי (אינדקס אוטומטי) |
FULLTEXT |
חיפוש טקסט מלא |
מתי להשתמש באינדקס?
✅ כדאי:
- עמודות ב-WHERE
- עמודות ב-JOIN
- עמודות ב-ORDER BY
- עמודות עם ערכים ייחודיים
❌ לא כדאי:
- טבלאות קטנות
- עמודות שמשתנות הרבה
- עמודות עם מעט ערכים שונים
ניהול אינדקסים
-- הצגת אינדקסים
SHOW INDEX FROM users;
-- מחיקת אינדקס
DROP INDEX idx_email ON users;
-- בדיקת ביצועים
EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
דוגמה מעשית
-- לפני: שאילתה איטית
SELECT * FROM orders WHERE user_id = 5;
-- סורק 1,000,000 שורות
-- יצירת אינדקס
CREATE INDEX idx_user_id ON orders(user_id);
-- אחרי: שאילתה מהירה
SELECT * FROM orders WHERE user_id = 5;
-- קופץ ישר לתוצאות
👁️ Views - תצוגות
מה זה View?
View הוא "טבלה וירטואלית" - שאילתה שמורה שמתנהגת כמו טבלה.
יצירת View
CREATE VIEW active_users AS
SELECT id, name, email
FROM users
WHERE status = 'active';
-- שימוש ב-View
SELECT * FROM active_users;
יתרונות
| יתרון | הסבר |
|---|---|
| פשטות | הסתרת מורכבות שאילתות |
| אבטחה | חשיפת חלק מהנתונים בלבד |
| שימוש חוזר | כתיבה פעם אחת, שימוש רב |
| עקביות | הגדרה אחידה לכל המשתמשים |
דוגמאות מעשיות
-- View עם JOIN
CREATE VIEW order_details AS
SELECT
o.id AS order_id,
u.name AS customer,
o.total,
o.status
FROM orders o
JOIN users u ON o.user_id = u.id;
-- View עם אגרגציה
CREATE VIEW sales_by_month AS
SELECT
YEAR(order_date) AS year,
MONTH(order_date) AS month,
SUM(total) AS revenue
FROM orders
GROUP BY YEAR(order_date), MONTH(order_date);
עדכון ומחיקה
-- עדכון View
CREATE OR REPLACE VIEW active_users AS
SELECT id, name, email, created_at
FROM users
WHERE status = 'active';
-- מחיקת View
DROP VIEW IF EXISTS active_users;
Updatable Views
-- View פשוט ניתן לעדכון
CREATE VIEW user_emails AS
SELECT id, email FROM users;
UPDATE user_emails SET email = '[email protected]' WHERE id = 1;
💡 לא כל View ניתן לעדכון - רק Views פשוטים ללא JOIN/GROUP BY
🗄️ מדריך מקיף: יצירת והקמת מסד נתונים מההתחלה
מדריך שלב-אחר-שלב ליצירת מסד נתונים מקצועי ומאורגן. מתאים למתחילים ומסביר כל שלב בפירוט.
📌 תוכן העניינים
- שלב התכנון - מה לפני הקוד
- יצירת מסד הנתונים
- יצירת טבלאות
- יצירת קשרים בין טבלאות
- אינדקסים לביצועים
- הוספת נתונים ראשוניים
- ניהול משתמשים והרשאות
- גיבוי ושחזור
- בדיקות ואימות
- צ'קליסט וטיפים
📋 שלב 1: תכנון מסד הנתונים
למה צריך לתכנן לפני לכתוב קוד?
תכנון נכון חוסך זמן, מונע טעויות ומבטיח שהמערכת תעבוד כמו שצריך. אל תדלג על שלב זה!
1.1 הגדרת דרישות המערכת
שאלות שחייבים לענות עליהן:
- מה המטרה של מסד הנתונים?
-
דוגמה: "לנהל חנות אינטרנט עם מוצרים, משתמשים והזמנות"
-
אילו נתונים נצטרך לשמור?
-
רשום רשימה: משתמשים, מוצרים, הזמנות, כתובות, תשלומים...
-
מי ישתמש במערכת?
-
לקוחות, מנהלים, ספקים...
-
אילו פעולות המערכת תצטרך לבצע?
- דוגמה: רישום משתמשים, הוספת מוצר לסל, ביצוע הזמנה, צפייה בהיסטוריית הזמנות...
1.2 זיהוי ישויות (Entities)
כל ישות = טבלה במסד הנתונים.
דוגמה למערכת חנות אינטרנט:
| ישות | מה היא מייצגת | תהפוך לטבלה |
|---|---|---|
| Users | משתמשים רשומים במערכת | users |
| Products | מוצרים למכירה | products |
| Orders | הזמנות שבוצעו | orders |
| Order Items | פריטים בתוך הזמנה | order_items |
| Categories | קטגוריות מוצרים | categories |
| Addresses | כתובות משלוח | addresses |
1.3 זיהוי תכונות (Attributes)
לכל ישות יש תכונות שיהפכו לעמודות בטבלה.
דוגמה: טבלת משתמשים (users)
| תכונה | סוג נתונים | למה צריך |
|---|---|---|
id |
INT | מזהה ייחודי |
name |
VARCHAR(100) | שם המשתמש |
email |
VARCHAR(255) | כתובת אימייל (לכניסה) |
password |
VARCHAR(255) | סיסמה מוצפנת |
phone |
VARCHAR(20) | מספר טלפון |
birth_date |
DATE | תאריך לידה |
is_active |
BOOLEAN | האם החשבון פעיל |
created_at |
TIMESTAMP | מתי נרשם |
1.4 שרטוט דיאגרמת קשרים (ER Diagram)
דיאגרמה פשוטה למערכת חנות:
┌─────────────────┐
│ Users │
│─────────────────│
│ id (PK) │
│ name │
│ email (UNIQUE) │
│ password │
│ phone │
│ created_at │
└────────┬────────┘
│
│ 1:N (משתמש אחד ← הזמנות רבות)
│
┌────────▼────────┐
│ Orders │
│─────────────────│
│ id (PK) │
│ user_id (FK)────┼─────┐
│ total_amount │ │
│ status │ │
│ order_date │ │
└────────┬────────┘ │
│ │
│ 1:N │
│ │
┌────────▼────────┐ │
│ Order_Items │ │
│─────────────────│ │
│ id (PK) │ │
│ order_id (FK) │ │
│ product_id (FK)─┼──┐ │
│ quantity │ │ │
│ price_at_order │ │ │
└─────────────────┘ │ │
│ │
┌────────────────┐ │ │
│ Products │ │ │
│────────────────│ │ │
│ id (PK) │◄──┘ │
│ name │ │
│ description │ │
│ price │ │
│ stock │ │
│ category_id(FK)│ │
└────────────────┘ │
│
קשר מסוג 1:N ─────┘
קיצורים: - PK = Primary Key (מפתח ראשי) - FK = Foreign Key (מפתח זר)
🏗️ שלב 2: יצירת מסד הנתונים
2.1 התחברות ל-MySQL
דרך 1: דרך שורת הפקודה (Terminal/CMD)
# התחברות כ-root
mysql -u root -p
דרך 2: דרך MySQL Workbench 1. פתח MySQL Workbench 2. לחץ על החיבור (Connection) 3. הזן סיסמה
2.2 יצירת מסד נתונים בסיסי
-- יצירת מסד נתונים חדש
CREATE DATABASE shop_db;
הסבר:
- CREATE DATABASE - פקודה ליצירת מסד נתונים
- shop_db - שם מסד הנתונים (אפשר לבחור כל שם)
2.3 יצירה עם בדיקה (מומלץ!)
-- יצירה רק אם המסד עדיין לא קיים
CREATE DATABASE IF NOT EXISTS shop_db;
למה זה חשוב? - מונע שגיאות אם המסד כבר קיים - שימושי בסקריפטים שרצים כמה פעמים
2.4 יצירה עם הגדרות קידוד (חובה לעברית!)
CREATE DATABASE shop_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
הסבר על הקידוד:
| הגדרה | מה זה | למה חשוב |
|---|---|---|
CHARACTER SET utf8mb4 |
ערכת תווים | תמיכה מלאה בעברית, אימוג'י ושפות אחרות |
COLLATE utf8mb4_unicode_ci |
כללי השוואה | מאפשר חיפוש ומיון נכון בעברית |
⚠️ חשוב: תמיד השתמש ב-utf8mb4 ולא ב-utf8 הישן!
2.5 שימוש במסד הנתונים
-- עבור למסד הנתונים שיצרת
USE shop_db;
מה זה עושה?
- מעתה כל הפקודות שתריץ יבוצעו על shop_db
2.6 בדיקת מסדי נתונים קיימים
-- הצגת כל מסדי הנתונים
SHOW DATABASES;
-- בדיקת איזה מסד בשימוש כרגע
SELECT DATABASE();
📊 שלב 3: יצירת טבלאות
3.1 הבנת סוגי נתונים (Data Types)
לפני שיוצרים טבלה, צריך לבחור את סוג הנתונים הנכון לכל עמודה.
📝 סוגי נתונים נפוצים
מספרים שלמים:
| סוג | טווח | שימוש |
|---|---|---|
TINYINT |
-128 עד 127 | גיל, כמות קטנה |
SMALLINT |
-32,768 עד 32,767 | מלאי מוצרים |
INT |
-2 מיליארד עד 2 מיליארד | מזהים (ID), כמויות |
BIGINT |
מספרים ענקיים | מזהים גלובליים |
טיפ: הוסף UNSIGNED למספרים חיוביים בלבד (מכפיל את הטווח)
age TINYINT UNSIGNED -- 0 עד 255
מספרים עשרוניים:
| סוג | הסבר | שימוש |
|---|---|---|
DECIMAL(p, s) |
מדויק! | מחירים, כסף - תמיד להשתמש! |
FLOAT |
קירוב | מדידות מדעיות |
DOUBLE |
קירוב מדויק יותר | חישובים מתמטיים |
דוגמה:
price DECIMAL(10, 2) -- 10 ספרות, 2 אחרי הנקודה
-- יכול לשמור: 99999999.99
טקסט:
| סוג | גודל מקסימלי | שימוש |
|---|---|---|
CHAR(n) |
n תווים קבוע | קודים קצרים (SKU, קוד מדינה) |
VARCHAR(n) |
עד n תווים | שמות, כתובות, אימיילים |
TEXT |
64KB | תיאורים ארוכים |
MEDIUMTEXT |
16MB | מאמרים |
LONGTEXT |
4GB | תוכן גדול מאוד |
דוגמאות:
name VARCHAR(100) -- שם מוצר
email VARCHAR(255) -- אימייל (תקן)
description TEXT -- תיאור מוצר
תאריכים ושעות:
| סוג | פורמט | שימוש |
|---|---|---|
DATE |
YYYY-MM-DD | תאריך לידה, תאריך תוקף |
TIME |
HH:MM:SS | שעת פתיחה |
DATETIME |
YYYY-MM-DD HH:MM:SS | תאריך ושעת הזמנה |
TIMESTAMP |
אוטומטי | created_at, updated_at |
דוגמה:
birth_date DATE -- 1990-05-15
order_date DATETIME -- 2026-01-04 14:30:00
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
אחרים:
| סוג | הסבר | דוגמה |
|---|---|---|
BOOLEAN |
TRUE/FALSE | is_active BOOLEAN |
ENUM |
רשימה קבועה | status ENUM('pending', 'paid') |
JSON |
נתוני JSON | settings JSON |
3.2 יצירת טבלה ראשונה - משתמשים
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
phone VARCHAR(20),
birth_date DATE,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
הסבר שורה אחר שורה:
id INT PRIMARY KEY AUTO_INCREMENT
- INT - מספר שלם
- PRIMARY KEY - מזהה ייחודי (לא יכול להיות אותו ID פעמיים)
- AUTO_INCREMENT - MySQL יעלה את המספר אוטומטית (1, 2, 3...)
name VARCHAR(100) NOT NULL
- VARCHAR(100) - טקסט עד 100 תווים
- NOT NULL - חובה למלא, לא יכול להיות ריק
email VARCHAR(255) UNIQUE NOT NULL
- UNIQUE - לא יכולים להיות 2 משתמשים עם אותו אימייל
- NOT NULL - חובה למלא
is_active BOOLEAN DEFAULT TRUE
- DEFAULT TRUE - אם לא מציינים ערך, יהיה TRUE
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
- CURRENT_TIMESTAMP - התאריך והשעה הנוכחיים אוטומטית
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
- מתעדכן אוטומטית כל פעם ששורה משתנה
3.3 יצירת טבלת מוצרים
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(200) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
stock INT UNSIGNED DEFAULT 0,
sku VARCHAR(50) UNIQUE,
is_available BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
שים לב:
- CHECK (price >= 0) - מוודא שהמחיר לא שלילי
- stock INT UNSIGNED - מלאי לא יכול להיות שלילי
- sku - מק"ט ייחודי למוצר
3.4 הבנת אילוצים (Constraints)
אילוצים = כללים שמבטיחים תקינות הנתונים.
| אילוץ | מה הוא עושה | דוגמה |
|---|---|---|
PRIMARY KEY |
מזהה ייחודי, לא ריק, אחד בלבד לטבלה | id INT PRIMARY KEY |
FOREIGN KEY |
קשר לטבלה אחרת | user_id INT, FOREIGN KEY... |
UNIQUE |
ערך ייחודי (אבל יכול להיות NULL) | email VARCHAR(255) UNIQUE |
NOT NULL |
חובה למלא | name VARCHAR(100) NOT NULL |
DEFAULT |
ערך ברירת מחדל | status VARCHAR(20) DEFAULT 'active' |
CHECK |
תנאי מותאם אישית | CHECK (age >= 18) |
AUTO_INCREMENT |
עלייה אוטומטית | id INT AUTO_INCREMENT |
דוגמאות מעשיות:
-- חובה למלא ולא יכול להיות ריק
email VARCHAR(255) NOT NULL
-- ייחודי - לא יכולים להיות 2 זהים
email VARCHAR(255) UNIQUE
-- שילוב: חובה למלא + ייחודי
email VARCHAR(255) UNIQUE NOT NULL
-- תנאי מותאם אישית
age TINYINT CHECK (age >= 18 AND age <= 120)
-- ערך ברירת מחדל
country VARCHAR(50) DEFAULT 'Israel'
-- עדכון אוטומטי
updated_at TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
🔗 שלב 4: יצירת קשרים בין טבלאות
4.1 הבנת סוגי קשרים
קשר One-to-Many (1:N) - הנפוץ ביותר
דוגמה: משתמש אחד יכול לבצע הרבה הזמנות.
Users (1) ←→ (N) Orders
משתמש 1 → הזמנה 1, הזמנה 2, הזמנה 3
איך מיישמים:
- בטבלת orders נוסיף עמודה user_id (מפתח זר)
קשר Many-to-Many (N:N)
דוגמה: הזמנה יכולה להכיל הרבה מוצרים, ומוצר יכול להיות בהרבה הזמנות.
Orders (N) ←→ (N) Products
איך מיישמים:
- יוצרים טבלת קשר (Junction Table) בשם order_items
- הטבלה מכילה: order_id + product_id
קשר One-to-One (1:1) - פחות נפוץ
דוגמה: כל משתמש יש לו פרופיל אחד בלבד.
Users (1) ←→ (1) Profiles
4.2 יישום קשר One-to-Many
יצירת טבלת הזמנות:
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
status ENUM('pending', 'paid', 'shipped', 'delivered', 'cancelled') DEFAULT 'pending',
shipping_address TEXT,
order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
-- יצירת הקשר לטבלת users
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE RESTRICT
ON UPDATE CASCADE
);
הסבר על המפתח הזר:
FOREIGN KEY (user_id) REFERENCES users(id)
- user_id בטבלה הזו מתייחס ל-id בטבלת users
- כל הזמנה חייבת להיות משויכת למשתמש קיים
4.3 הבנת Referential Actions
מה קורה כשמוחקים או מעדכנים רשומה שקשורה לרשומות אחרות?
ON DELETE RESTRICT -- מה קורה כשמוחקים משתמש
ON UPDATE CASCADE -- מה קורה כשמעדכנים את ה-ID
| פעולה | מה קורה | מתי להשתמש |
|---|---|---|
RESTRICT |
מונע מחיקה/עדכון אם יש רשומות קשורות | ברירת מחדל - הכי בטוח |
CASCADE |
מוחק/מעדכן אוטומטית את כל הרשומות הקשורות | כשרוצים מחיקה מלאה |
SET NULL |
מציב NULL ברשומות הקשורות | כשהקשר אופציונלי |
NO ACTION |
כמו RESTRICT |
דוגמאות מעשיות:
-- אם מוחקים משתמש, מחק את כל ההזמנות שלו
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
-- אם מוחקים משתמש, לא תן למחוק אם יש לו הזמנות
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE RESTRICT
-- אם מוחקים קטגוריה, שים NULL במוצרים
FOREIGN KEY (category_id) REFERENCES categories(id)
ON DELETE SET NULL
4.4 יישום קשר Many-to-Many
יצירת טבלת קשר (Junction Table):
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT UNSIGNED NOT NULL DEFAULT 1,
price_at_order DECIMAL(10, 2) NOT NULL,
-- קשר להזמנה
FOREIGN KEY (order_id) REFERENCES orders(id)
ON DELETE CASCADE,
-- קשר למוצר
FOREIGN KEY (product_id) REFERENCES products(id)
ON DELETE RESTRICT,
-- מניעת כפילויות - אותו מוצר באותה הזמנה
UNIQUE KEY unique_order_product (order_id, product_id)
);
למה price_at_order?
- שומרים את המחיר בזמן ההזמנה
- אם המחיר במוצר משתנה, ההזמנות הישנות לא ישתנו
למה CASCADE ב-order_id?
- אם מוחקים הזמנה, נמחק גם את הפריטים שלה
למה RESTRICT ב-product_id?
- לא נותנים למחוק מוצר שיש לו הזמנות
4.5 דוגמה מלאה: יצירת כל הטבלאות ביחד
-- 1. טבלת משתמשים
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 2. טבלת קטגוריות
CREATE TABLE categories (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT
);
-- 3. טבלת מוצרים
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
category_id INT,
name VARCHAR(200) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT UNSIGNED DEFAULT 0,
FOREIGN KEY (category_id) REFERENCES categories(id)
ON DELETE SET NULL
);
-- 4. טבלת הזמנות
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
total_amount DECIMAL(10, 2) DEFAULT 0.00,
status ENUM('pending', 'paid', 'shipped', 'delivered') DEFAULT 'pending',
order_date DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE RESTRICT
);
-- 5. טבלת פריטי הזמנה
CREATE TABLE order_items (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT UNSIGNED NOT NULL DEFAULT 1,
price_at_order DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
);
📇 שלב 5: יצירת אינדקסים
5.1 מה זה אינדקס ולמה צריך אותו?
אינדקס = תוכן עניינים של הטבלה
בלי אינדקס:
חיפוש "[email protected]" בטבלה עם מיליון שורות
→ MySQL צריך לעבור על כל שורה = איטי!
עם אינדקס:
MySQL קופץ ישר לשורה הנכונה = מהיר!
אנלוגיה: - בלי אינדקס = לחפש מילה בספר ללא תוכן עניינים (עוברים עמוד אחר עמוד) - עם אינדקס = יש תוכן עניינים שמראה בדיוק באיזה עמוד המילה נמצאת
5.2 מתי ליצור אינדקס?
✅ כדאי ליצור אינדקס על:
-
עמודות ב-WHERE
-- אם רץ הרבה: SELECT * FROM users WHERE email = '[email protected]'; -- צור אינדקס על email -
עמודות ב-JOIN
-- אם רץ הרבה: SELECT * FROM orders o JOIN users u ON o.user_id = u.id; -- צור אינדקס על user_id -
עמודות ב-ORDER BY
-- אם רץ הרבה: SELECT * FROM products ORDER BY price; -- צור אינדקס על price
❌ לא כדאי ליצור אינדקס על:
- טבלאות קטנות (פחות מ-1000 שורות)
- עמודות שמשתנות תדיר (כל שינוי מעדכן את האינדקס)
- עמודות עם ערכים זהים רבים (TRUE/FALSE)
5.3 סוגי אינדקסים
אינדקס בסיסי (Index)
-- אינדקס על עמודה אחת
CREATE INDEX idx_users_email ON users(email);
-- אינדקס על כמה עמודות (Composite Index)
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);
אינדקס ייחודי (Unique Index)
-- מבטיח ייחודיות + מאיץ חיפושים
CREATE UNIQUE INDEX idx_products_sku ON products(sku);
שים לב: PRIMARY KEY ו-UNIQUE יוצרים אינדקס אוטומטית!
5.4 דוגמאות מעשיות
-- חיפושים לפי אימייל (נפוץ מאוד)
CREATE INDEX idx_users_email ON users(email);
-- סינון לפי סטטוס
CREATE INDEX idx_orders_status ON orders(status);
-- חיפוש הזמנות של משתמש ספציפי
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- מיון לפי תאריך
CREATE INDEX idx_orders_date ON orders(order_date);
-- חיפוש במוצרים לפי שם (Full-Text Search)
CREATE FULLTEXT INDEX idx_products_name ON products(name, description);
5.5 איך לדעת אם אינדקס עוזר?
בדיקה עם EXPLAIN:
-- ראה איך MySQL מריץ את השאילתה
EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
תוצאה:
| type | possible_keys | key | rows |
|-------|------------------|------------------|------|
| ref | idx_users_email | idx_users_email | 1 |
keyמציג את האינדקס שבשימושrows= כמה שורות נבדקו (רוצים מספר קטן)
5.6 ניהול אינדקסים
-- הצגת כל האינדקסים בטבלה
SHOW INDEX FROM users;
-- מחיקת אינדקס
DROP INDEX idx_users_email ON users;
-- הוספת אינדקס לטבלה קיימת
ALTER TABLE products ADD INDEX idx_price (price);
🔒 שלב 6: הכנסת נתונים ראשוניים
6.1 הכנסת נתונים בסיסית
-- הכנסת משתמש אחד
INSERT INTO users (name, email, password)
VALUES ('ישראל ישראלי', '[email protected]', 'hashed_password_123');
-- הכנסת כמה משתמשים בבת אחת (יעיל יותר!)
INSERT INTO users (name, email, password) VALUES
('שרה כהן', '[email protected]', 'hashed_password_456'),
('דוד לוי', '[email protected]', 'hashed_password_789'),
('מיכל אברהם', '[email protected]', 'hashed_password_012');
6.2 הכנסת קטגוריות ומוצרים
-- קטגוריות
INSERT INTO categories (name, description) VALUES
('אלקטרוניקה', 'מוצרי חשמל ואלקטרוניקה'),
('ספרים', 'ספרים בעברית ובאנגלית'),
('ביגוד', 'בגדים לגברים ונשים');
-- מוצרים (שים לב ל-category_id)
INSERT INTO products (category_id, name, price, stock, sku) VALUES
(1, 'לפטופ Dell XPS 13', 4500.00, 10, 'DELL-XPS-13'),
(1, 'עכבר אלחוטי Logitech', 150.00, 50, 'LOG-MX-MASTER'),
(1, 'מסך 27 אינץ Samsung', 1200.00, 15, 'SAM-27-4K'),
(2, 'הארי פוטר - סט מלא', 350.00, 20, 'BOOK-HP-SET'),
(3, 'חולצה כחולה', 99.90, 100, 'SHIRT-BLUE-M');
6.3 הכנסת הזמנות ופריטים
-- הזמנה ראשונה (משתמש 1)
INSERT INTO orders (user_id, total_amount, status)
VALUES (1, 4650.00, 'paid');
-- קבלת ה-ID של ההזמנה שיצרנו
SET @order_id = LAST_INSERT_ID();
-- הכנסת פריטים להזמנה
INSERT INTO order_items (order_id, product_id, quantity, price_at_order) VALUES
(@order_id, 1, 1, 4500.00), -- לפטופ
(@order_id, 2, 1, 150.00); -- עכבר
הסבר:
- LAST_INSERT_ID() - מחזיר את ה-ID האחרון שנוסף
- @order_id - משתנה שמחזיק את ה-ID
6.4 סקריפט מלא להכנסת נתונים לדוגמה
-- משתמשים
INSERT INTO users (name, email, password) VALUES
('ישראל ישראלי', '[email protected]', 'pass123'),
('שרה כהן', '[email protected]', 'pass456'),
('דוד לוי', '[email protected]', 'pass789');
-- קטגוריות
INSERT INTO categories (name) VALUES
('אלקטרוניקה'),
('ספרים'),
('ביגוד');
-- מוצרים
INSERT INTO products (category_id, name, price, stock) VALUES
(1, 'לפטופ', 4500.00, 10),
(1, 'עכבר', 150.00, 50),
(2, 'ספר SQL למתחילים', 120.00, 30),
(3, 'חולצה', 99.90, 100);
-- הזמנה לדוגמה
INSERT INTO orders (user_id, total_amount, status) VALUES (1, 4650.00, 'paid');
INSERT INTO order_items (order_id, product_id, quantity, price_at_order) VALUES
(1, 1, 1, 4500.00),
(1, 2, 1, 150.00);
🛡️ שלב 7: ניהול משתמשים והרשאות
7.1 למה צריך משתמשים נפרדים?
סיבות אבטחה:
- אפליקציה לא צריכה להתחבר כ-root (יותר מדי הרשאות = סיכון)
- כל אפליקציה תתחבר עם משתמש משלה
- אם מישהו פורץ לאפליקציה, הוא לא יוכל למחוק את כל המסד
7.2 יצירת משתמש חדש
-- יצירת משתמש לאפליקציה
CREATE USER 'shop_app'@'localhost' IDENTIFIED BY 'SecurePassword123!';
הסבר:
- shop_app - שם המשתמש
- localhost - המשתמש יכול להתחבר רק מהמחשב המקומי
- IDENTIFIED BY - הסיסמה
משתמש שיכול להתחבר מכל מקום:
CREATE USER 'shop_app'@'%' IDENTIFIED BY 'SecurePassword123!';
7.3 הענקת הרשאות
הרשאות בסיסיות לאפליקציה
-- הרשאות קריאה וכתיבה על כל הטבלאות
GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'shop_app'@'localhost';
הסבר:
- SELECT - קריאת נתונים
- INSERT - הוספת נתונים
- UPDATE - עדכון נתונים
- DELETE - מחיקת נתונים
- shop_db.* - כל הטבלאות במסד shop_db
הרשאות לטבלה ספציפית
-- הרשאת קריאה בלבד לטבלת מוצרים
GRANT SELECT ON shop_db.products TO 'readonly_user'@'localhost';
-- הרשאות מלאות (כולל DROP, CREATE)
GRANT ALL PRIVILEGES ON shop_db.* TO 'admin_user'@'localhost';
הרשאות מתקדמות
-- הרשאה ליצור טבלאות
GRANT CREATE ON shop_db.* TO 'developer'@'localhost';
-- הרשאה לשנות מבנה טבלאות
GRANT ALTER ON shop_db.* TO 'developer'@'localhost';
-- הרשאה ליצור אינדקסים
GRANT INDEX ON shop_db.* TO 'developer'@'localhost';
7.4 שלילת הרשאות
-- שלילת הרשאת מחיקה
REVOKE DELETE ON shop_db.* FROM 'shop_app'@'localhost';
-- שלילת כל ההרשאות
REVOKE ALL PRIVILEGES ON shop_db.* FROM 'shop_app'@'localhost';
7.5 הפעלת השינויים
-- חובה להריץ לאחר כל שינוי בהרשאות!
FLUSH PRIVILEGES;
7.6 בדיקת הרשאות
-- הצגת כל המשתמשים
SELECT User, Host FROM mysql.user;
-- הצגת הרשאות של משתמש ספציפי
SHOW GRANTS FOR 'shop_app'@'localhost';
7.7 מחיקת משתמש
DROP USER 'shop_app'@'localhost';
7.8 דוגמה מלאה: הגדרת משתמשים למערכת
-- 1. משתמש לאפליקציה (קריאה + כתיבה בלבד)
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'AppPass123!';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'app_user'@'localhost';
-- 2. משתמש לקריאה בלבד (דוחות, Analytics)
CREATE USER 'readonly_user'@'localhost' IDENTIFIED BY 'ReadOnlyPass456!';
GRANT SELECT ON shop_db.* TO 'readonly_user'@'localhost';
-- 3. משתמש למפתח (הרשאות מלאות מלבד DROP)
CREATE USER 'developer'@'localhost' IDENTIFIED BY 'DevPass789!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX
ON shop_db.* TO 'developer'@'localhost';
-- הפעלת ההרשאות
FLUSH PRIVILEGES;
💾 שלב 8: גיבוי ושחזור
8.1 למה חשוב לגבות?
- מניעת אובדן נתונים במקרה של תקלה
- שחזור אחרי טעות (למשל מחיקה בטעות)
- העתקת המסד לסביבת פיתוח/בדיקה
- העברה לשרת אחר
8.2 גיבוי מסד נתונים מלא (mysqldump)
דרך שורת הפקודה (CMD/Terminal):
# גיבוי של מסד נתונים אחד
mysqldump -u root -p shop_db > shop_db_backup_2026-01-04.sql
# גיבוי של כל מסדי הנתונים
mysqldump -u root -p --all-databases > all_databases_backup.sql
# גיבוי עם דחיסה (חוסך מקום)
mysqldump -u root -p shop_db | gzip > shop_db_backup.sql.gz
הסבר:
- -u root - משתמש
- -p - תבקש סיסמה
- shop_db - שם המסד
- > - שמירה לקובץ
8.3 גיבוי טבלה ספציפית
# גיבוי של טבלה אחת בלבד
mysqldump -u root -p shop_db users > users_backup.sql
# גיבוי של כמה טבלאות
mysqldump -u root -p shop_db users orders products > tables_backup.sql
8.4 גיבוי ללא נתונים (רק מבנה)
# גיבוי המבנה בלבד (ללא הנתונים)
mysqldump -u root -p --no-data shop_db > shop_db_structure.sql
שימושי כאשר רוצים להעתיק את המבנה לסביבה חדשה.
8.5 שחזור מגיבוי
שחזור מסד נתונים מלא:
# שחזור (המסד חייב להיות קיים!)
mysql -u root -p shop_db < shop_db_backup_2026-01-04.sql
שחזור כולל יצירת המסד:
# 1. יצירת מסד חדש
mysql -u root -p -e "CREATE DATABASE shop_db_restored;"
# 2. שחזור הנתונים
mysql -u root -p shop_db_restored < shop_db_backup.sql
שחזור מקובץ דחוס:
gunzip < shop_db_backup.sql.gz | mysql -u root -p shop_db
8.6 גיבוי אוטומטי (Cron Job ב-Linux)
יצירת סקריפט גיבוי:
#!/bin/bash
# backup_db.sh
# הגדרות
DB_USER="root"
DB_PASS="your_password"
DB_NAME="shop_db"
BACKUP_DIR="/backups/mysql"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
# יצירת גיבוי
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz
# מחיקת גיבויים ישנים (מעל 7 ימים)
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
הפעלה אוטומטית כל יום ב-2:00 בלילה:
# פתיחת עורך cron
crontab -e
# הוספת השורה:
0 2 * * * /path/to/backup_db.sh
8.7 גיבוי ב-Windows (Task Scheduler)
יצירת קובץ .bat:
@echo off
REM backup_db.bat
set DB_USER=root
set DB_PASS=your_password
set DB_NAME=shop_db
set BACKUP_DIR=C:\backups\mysql
set DATE=%date:~-4,4%-%date:~-7,2%-%date:~-10,2%
"C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqldump.exe" -u %DB_USER% -p%DB_PASS% %DB_NAME% > %BACKUP_DIR%\%DB_NAME%_%DATE%.sql
לאחר מכן, צור Task ב-Task Scheduler שירוץ את הקובץ מדי יום.
✅ שלב 9: בדיקות ואימות
9.1 בדיקת מבנה הטבלאות
-- רשימת כל הטבלאות במסד הנתונים
SHOW TABLES;
-- מבנה מפורט של טבלה
DESCRIBE users;
-- או
SHOW COLUMNS FROM users;
-- הצגת פקודת CREATE המלאה
SHOW CREATE TABLE users;
9.2 בדיקת מפתחות זרים
-- הצגת כל המפתחות הזרים בטבלה
SELECT
TABLE_NAME,
COLUMN_NAME,
CONSTRAINT_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = 'shop_db'
AND REFERENCED_TABLE_NAME IS NOT NULL;
9.3 בדיקת אינדקסים
-- הצגת כל האינדקסים בטבלה
SHOW INDEX FROM users;
-- בדיקה אם אינדקס משמש בשאילתה
EXPLAIN SELECT * FROM users WHERE email = '[email protected]';
9.4 בדיקת קשרים בין טבלאות
-- בדיקה שההזמנות קשורות למשתמשים
SELECT
u.name AS user_name,
COUNT(o.id) AS total_orders
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;
-- בדיקה שפריטי הזמנה קשורים נכון
SELECT
o.id AS order_id,
p.name AS product_name,
oi.quantity,
oi.price_at_order
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id;
9.5 בדיקת תקינות נתונים
-- בדיקה שאין מחירים שליליים
SELECT * FROM products WHERE price < 0;
-- בדיקה שאין אימיילים כפולים
SELECT email, COUNT(*)
FROM users
GROUP BY email
HAVING COUNT(*) > 1;
-- בדיקה שכל ההזמנות קשורות למשתמשים קיימים
SELECT o.*
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE u.id IS NULL;
9.6 בדיקת ביצועים
-- כמה שורות בכל טבלה
SELECT
TABLE_NAME,
TABLE_ROWS
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'shop_db';
-- גודל הטבלאות
SELECT
TABLE_NAME,
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'shop_db'
ORDER BY (DATA_LENGTH + INDEX_LENGTH) DESC;
📝 צ'קליסט סופי
✅ תכנון
- הגדרתי את דרישות המערכת
- זיהיתי את כל הישויות (טבלאות)
- שרטטתי דיאגרמת ER
- הגדרתי את הקשרים בין הטבלאות
- בחרתי סוגי נתונים מתאימים לכל עמודה
✅ יצירה
- יצרתי את מסד הנתונים עם UTF8MB4
- יצרתי את כל הטבלאות
- הוספתי Primary Keys לכל טבלה
- יצרתי Foreign Keys (מפתחות זרים)
- הוספתי אילוצים (NOT NULL, UNIQUE, CHECK)
- הגדרתי ערכי ברירת מחדל (DEFAULT)
- הוספתי שדות created_at ו-updated_at
✅ אופטימיזציה
- יצרתי אינדקסים על עמודות בשימוש תכוף
- בדקתי עם EXPLAIN ששאילתות משתמשות באינדקסים
- הוספתי אינדקסים על מפתחות זרים
✅ נתונים
- הוספתי נתונים ראשוניים לבדיקה
- בדקתי שהקשרים בין הטבלאות עובדים
✅ אבטחה
- יצרתי משתמש נפרד לאפליקציה (לא root)
- הענקתי רק את ההרשאות הנדרשות
- הרצתי FLUSH PRIVILEGES
✅ גיבוי ותחזוקה
- ביצעתי גיבוי ראשוני
- בדקתי ששחזור מגיבוי עובד
- הגדרתי גיבוי אוטומטי
✅ בדיקות
- בדקתי את מבנה כל הטבלאות (DESCRIBE)
- בדקתי שהמפתחות הזרים עובדים
- הרצתי שאילתות JOIN לבדיקת קשרים
- בדקתי שאין נתונים לא תקינים
💡 טיפים וכללי אצבע
כללי שמות
-- ✅ טוב
users, user_id, created_at
-- ❌ לא טוב
Users, userId, CreatedAt, tbl_users
המלצות:
- שמות טבלאות ברבים באנגלית (users, products)
- שמות עמודות ב-snake_case (user_id, created_at)
- מפתחות זרים עם סיומת _id (user_id, product_id)
- בוליאנים עם קידומת is_ (is_active, is_verified)
ערכי ברירת מחדל חשובים
-- תמיד הוסף:
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
-- לבוליאנים:
is_active BOOLEAN DEFAULT TRUE
-- למספרים:
balance DECIMAL(10,2) DEFAULT 0.00
quantity INT DEFAULT 0
טיפים לביצועים
-
אל תשתמש ב-
SELECT *-- ❌ לא טוב SELECT * FROM products; -- ✅ טוב SELECT id, name, price FROM products; -
השתמש ב-LIMIT בשאילתות גדולות
SELECT * FROM orders ORDER BY created_at DESC LIMIT 100; -
אינדקס על עמודות ב-WHERE ו-JOIN
CREATE INDEX idx_orders_user_id ON orders(user_id);
טיפים לאבטחה
-
לעולם אל תשמור סיסמאות בטקסט פשוט!
-- ❌ מסוכן! INSERT INTO users (password) VALUES ('123456'); -- ✅ מוצפן INSERT INTO users (password) VALUES ('$2y$10$...'); -- bcrypt hash -
השתמש ב-Prepared Statements באפליקציה
-
מונע SQL Injection
-
הגבל הרשאות משתמשים
-- האפליקציה לא צריכה DROP או CREATE GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'app_user'@'localhost';
טיפים לתחזוקה
- גבה באופן קבוע
- יומי: גיבוי מלא
- שבועי: גיבוי לשרת חיצוני
-
חודשי: גיבוי ארכיון
-
עקוב אחרי גודל הטבלאות
SELECT TABLE_NAME, ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS size_mb FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'shop_db' ORDER BY size_mb DESC; -
נקה נתונים ישנים
-- מחיקת הזמנות מבוטלות מעל 90 יום DELETE FROM orders WHERE status = 'cancelled' AND order_date < DATE_SUB(NOW(), INTERVAL 90 DAY);
🎓 סיכום
סדר פעולות ליצירת מסד נתונים:
- תכנון - הגדרה של ישויות, תכונות וקשרים
- יצירת מסד -
CREATE DATABASEעם UTF8MB4 - יצירת טבלאות - עם סוגי נתונים ואילוצים מתאימים
- קשרים - הוספת Foreign Keys
- אינדקסים - לשיפור ביצועים
- נתונים - הכנסת נתונים ראשוניים
- משתמשים - יצירת משתמשים עם הרשאות
- גיבוי - ביצוע גיבוי ראשוני
- בדיקות - אימות שהכל עובד
זכור: תכנון טוב בהתחלה חוסך הרבה כאב ראש בהמשך!