מפתח

ברוכים הבאים!

פרויקט זה מיועד ללימוד שפת SQL למתחילים. הפרויקט כולל תיעוד מפורט בעברית ודוגמאות קוד מעשיות.


📋 תוכן עניינים

תיעוד (docs/)

  1. רקע והיסטוריה - מהו SQL ומאיפה הוא הגיע
  2. יסודות - מושגים בסיסיים שחייבים לדעת
  3. סינטקס וצורת כתיבה - איך כותבים שאילתות SQL
  4. סוגי נתונים - הטיפוסים הנפוצים ב-SQL
  5. שאילתות SELECT - קריאת נתונים מהטבלאות
  6. חיבורי טבלאות - JOIN וסוגיו השונים
  7. פונקציות צבירה - COUNT, SUM, AVG ועוד
  8. UPDATE ו-DELETE - עדכון ומחיקת נתונים
  9. טרנזקציות - ACID ועבודה בטוחה
  10. אינדקסים - שיפור ביצועים
  11. Views - תצוגות וירטואליות

דוגמאות קוד (examples/)

  1. 01-basics.sql - תחביר בסיסי והערות
  2. 02-create.sql - יצירת מסדי נתונים וטבלאות
  3. 03-insert.sql - הכנסת נתונים
  4. 04-select.sql - שאילתות בסיסיות
  5. 05-where.sql - סינון וחיפוש נתונים
  6. 06-joins.sql - חיבור טבלאות
  7. 07-aggregation.sql - פונקציות צבירה וקיבוץ
  8. 08-subqueries.sql - שאילתות מקוננות
  9. 09-update-delete.sql - עדכון ומחיקה
  10. 10-transactions.sql - טרנזקציות
  11. 11-indexes.sql - אינדקסים
  12. 12-views.sql - תצוגות

🔧 דרישות מקדימות

לפני שמתחילים, מומלץ שיהיה מותקן אחד מהבאים:

💡 טיפ: למתחילים מומלץ להתחיל עם SQLite או להשתמש בסביבה אונליין כמו SQLite Online


🚀 התחלה מהירה

אפשרות 1: סביבה אונליין (מומלץ למתחילים)

פשוט גשו ל-SQLite Online והעתיקו את הדוגמאות מתיקיית examples/.

אפשרות 2: התקנה מקומית

  1. התקינו את אחד ממסדי הנתונים הנ"ל
  2. פתחו את הממשק שלו (MySQL Workbench, pgAdmin, וכו')
  3. הריצו את הקבצים מתיקיית examples/

📚 סדר לימוד מומלץ

  1. התחילו מהרקע - הבינו מה זה SQL ולמה זה חשוב
  2. למדו את היסודות - טבלאות, עמודות, שורות ומפתחות
  3. הבינו את התחביר - כללי כתיבה נכונה
  4. תרגלו SELECT - קריאת נתונים היא הבסיס
  5. הוסיפו WHERE - למדו לסנן נתונים
  6. שלטו ב-JOIN - חיבור טבלאות הוא קריטי
  7. בנו שאילתות מורכבות - צברו ביטחון!

💡 טיפים למתחילים

טיפ 1: תמיד התחילו עם SELECT קטן לפני שאילתה גדולה

טיפ 2: השתמשו ב-LIMIT כדי לא להציף את עצמכם בתוצאות

טיפ 3: כתבו כל מילת מפתח בשורה נפרדת - זה קריא יותר

טיפ 4: שמרו על עקביות בסגנון הכתיבה שלכם


🔗 משאבים נוספים


בהצלחה בלימוד! 🎓

💻 מדריך מלא: פקודות טרמינל ל-MySQL

מדריך מקיף לעבודה עם MySQL דרך שורת הפקודה (Terminal/CMD), כולל Docker, התקנה מקומית ופקודות בסיסיות.


📌 תוכן עניינים

  1. התחברות ל-MySQL - סקירה כללית
  2. עבודה עם Docker
  3. עבודה עם MySQL מקומי
  4. פקודות MySQL בסיסיות
  5. פקודות מתקדמות
  6. טיפים ופתרון בעיות

🔌 שיטות התחברות ל-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
  1. הורד את MySQL Community Server:
  2. לך ל-dev.mysql.com/downloads
  3. בחר את הגרסה ל-Windows
  4. הורד ה-Installer

  5. התקן:

  6. הרץ את ה-Installer
  7. בחר "Developer Default" או "Server Only"
  8. הגדר סיסמה ל-root
  9. השאר את כל ההגדרות כברירת מחדל

  10. בדיקה:

    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';

🔗 קישורים שימושיים


המשך לרקע והיסטוריה → | חזרה למדריך הראשי

📜 רקע והיסטוריה של 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?

  1. דרישה גבוהה בשוק העבודה - כמעט כל תפקיד טכני דורש SQL
  2. שפה אוניברסלית - עובדת על רוב מסדי הנתונים
  3. קל ללמוד - תחביר קריא ואינטואיטיבי
  4. כוח רב - גישה לנתונים בשניות
  5. יציבות - 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;

⚡ טיפים לכתיבה נקייה

  1. עקביות - בחרו סגנון ושמרו עליו
  2. הזחה - השתמשו ב-4 רווחים או TAB
  3. שורות - פקודה חדשה = שורה חדשה
  4. הערות - הסבירו את הלוגיקה, לא את הקוד
  5. שמות משמעותיים - 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)

⚡ טיפים

  1. בחרו את הסוג הקטן ביותר שמספיק לצרכים שלכם
  2. לכסף: DECIMAL - לעולם לא FLOAT
  3. לטקסט: VARCHAR - אלא אם צריך TEXT
  4. למפתחות: INT - אלא אם צריך BIGINT
  5. זכרו - סוגי נתונים משפיעים על ביצועים!

← סינטקס | המשך לשאילתות →

🔍 שאילתות 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;

💡 טיפים

  1. **הימנעו מ-SELECT *** - ציינו עמודות ספציפיות
  2. השתמשו ב-LIMIT - במיוחד בפיתוח
  3. בדקו NULL עם IS NULL, לא עם =
  4. סדר הפקודות - SELECT, FROM, WHERE, ORDER BY, LIMIT

← סוגי נתונים | המשך ל-JOIN →

🔗 חיבורי טבלאות (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;

← JOIN | חזור לתוכן העניינים →

✏️ 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;

🛡️ טיפים לבטיחות

  1. תמיד SELECT לפני UPDATE/DELETE

    -- קודם בדקו מה ייפגע
    SELECT * FROM users WHERE status = 'inactive';
    
    -- ואז עדכנו/מחקו
    DELETE FROM users WHERE status = 'inactive';
  2. השתמשו ב-LIMIT

    DELETE FROM logs WHERE year < 2020 LIMIT 100;
  3. עבדו בטרנזקציה

    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;  -- הפעלה

← UPDATE ו-DELETE | המשך לאינדקסים →

⚡ אינדקסים (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 →

👁️ 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. שלב התכנון - מה לפני הקוד
  2. יצירת מסד הנתונים
  3. יצירת טבלאות
  4. יצירת קשרים בין טבלאות
  5. אינדקסים לביצועים
  6. הוספת נתונים ראשוניים
  7. ניהול משתמשים והרשאות
  8. גיבוי ושחזור
  9. בדיקות ואימות
  10. צ'קליסט וטיפים

📋 שלב 1: תכנון מסד הנתונים

למה צריך לתכנן לפני לכתוב קוד?

תכנון נכון חוסך זמן, מונע טעויות ומבטיח שהמערכת תעבוד כמו שצריך. אל תדלג על שלב זה!


1.1 הגדרת דרישות המערכת

שאלות שחייבים לענות עליהן:

  1. מה המטרה של מסד הנתונים?
  2. דוגמה: "לנהל חנות אינטרנט עם מוצרים, משתמשים והזמנות"

  3. אילו נתונים נצטרך לשמור?

  4. רשום רשימה: משתמשים, מוצרים, הזמנות, כתובות, תשלומים...

  5. מי ישתמש במערכת?

  6. לקוחות, מנהלים, ספקים...

  7. אילו פעולות המערכת תצטרך לבצע?

  8. דוגמה: רישום משתמשים, הוספת מוצר לסל, ביצוע הזמנה, צפייה בהיסטוריית הזמנות...

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 מתי ליצור אינדקס?

✅ כדאי ליצור אינדקס על:

  1. עמודות ב-WHERE

    -- אם רץ הרבה:
    SELECT * FROM users WHERE email = '[email protected]';
    -- צור אינדקס על email
  2. עמודות ב-JOIN

    -- אם רץ הרבה:
    SELECT * FROM orders o JOIN users u ON o.user_id = u.id;
    -- צור אינדקס על user_id
  3. עמודות ב-ORDER BY

    -- אם רץ הרבה:
    SELECT * FROM products ORDER BY price;
    -- צור אינדקס על price

❌ לא כדאי ליצור אינדקס על:

  1. טבלאות קטנות (פחות מ-1000 שורות)
  2. עמודות שמשתנות תדיר (כל שינוי מעדכן את האינדקס)
  3. עמודות עם ערכים זהים רבים (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

טיפים לביצועים

  1. אל תשתמש ב-SELECT *

    -- ❌ לא טוב
    SELECT * FROM products;
    
    -- ✅ טוב
    SELECT id, name, price FROM products;
  2. השתמש ב-LIMIT בשאילתות גדולות

    SELECT * FROM orders ORDER BY created_at DESC LIMIT 100;
  3. אינדקס על עמודות ב-WHERE ו-JOIN

    CREATE INDEX idx_orders_user_id ON orders(user_id);

טיפים לאבטחה

  1. לעולם אל תשמור סיסמאות בטקסט פשוט!

    -- ❌ מסוכן!
    INSERT INTO users (password) VALUES ('123456');
    
    -- ✅ מוצפן
    INSERT INTO users (password) VALUES ('$2y$10$...');  -- bcrypt hash
  2. השתמש ב-Prepared Statements באפליקציה

  3. מונע SQL Injection

  4. הגבל הרשאות משתמשים

    -- האפליקציה לא צריכה DROP או CREATE
    GRANT SELECT, INSERT, UPDATE, DELETE ON shop_db.* TO 'app_user'@'localhost';

טיפים לתחזוקה

  1. גבה באופן קבוע
  2. יומי: גיבוי מלא
  3. שבועי: גיבוי לשרת חיצוני
  4. חודשי: גיבוי ארכיון

  5. עקוב אחרי גודל הטבלאות

    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;
  6. נקה נתונים ישנים

    -- מחיקת הזמנות מבוטלות מעל 90 יום
    DELETE FROM orders
    WHERE status = 'cancelled'
    AND order_date < DATE_SUB(NOW(), INTERVAL 90 DAY);

🎓 סיכום

סדר פעולות ליצירת מסד נתונים:

  1. תכנון - הגדרה של ישויות, תכונות וקשרים
  2. יצירת מסד - CREATE DATABASE עם UTF8MB4
  3. יצירת טבלאות - עם סוגי נתונים ואילוצים מתאימים
  4. קשרים - הוספת Foreign Keys
  5. אינדקסים - לשיפור ביצועים
  6. נתונים - הכנסת נתונים ראשוניים
  7. משתמשים - יצירת משתמשים עם הרשאות
  8. גיבוי - ביצוע גיבוי ראשוני
  9. בדיקות - אימות שהכל עובד

זכור: תכנון טוב בהתחלה חוסך הרבה כאב ראש בהמשך!


← רשומות מוגדרות (Views) | המשך למדריכים נוספים →