أساسيات PHP

SQL: إدراج واختيار البيانات

13 دقيقة الدرس 32 من 45

إدراج البيانات باستخدام INSERT

عبارة INSERT INTO تضيف صفوف (سجلات) جديدة إلى جدول.

الصيغة الأساسية

INSERT INTO table_name (column1, column2, column3)
VALUES (value1, value2, value3);

مثال: إدراج مستخدم واحد

INSERT INTO users (username, email, password)
VALUES ('john_doe', 'john@example.com', 'hashed_password_here');

ملاحظات مهمة

  • قيم النصوص يجب أن تكون محاطة بعلامات اقتباس مفردة: 'text'
  • الأرقام لا تحتاج إلى علامات اقتباس: 25, 19.99
  • أعمدة AUTO_INCREMENT (مثل id) يتم إنشاؤها تلقائياً - لا تقم بتضمينها
  • الأعمدة ذات القيم الافتراضية (مثل created_at) يمكن حذفها

الإدراج بدون أسماء الأعمدة

إذا قدمت قيماً لجميع الأعمدة بالترتيب الدقيق الذي تم تعريفها به:

INSERT INTO users
VALUES (NULL, 'jane_doe', 'jane@example.com', 'hashed_password', NOW());
-- NULL لـ AUTO_INCREMENT id
-- NOW() للطابع الزمني

أفضل ممارسة: حدد دائماً أسماء الأعمدة بشكل صريح. هذا يجعل كودك أكثر قابلية للقراءة ويمنع الأخطاء إذا تغير هيكل الجدول.

إدراج صفوف متعددة

أدرج سجلات متعددة في استعلام واحد لأداء أفضل:

INSERT INTO users (username, email, password)
VALUES
    ('alice', 'alice@example.com', 'password1'),
    ('bob', 'bob@example.com', 'password2'),
    ('charlie', 'charlie@example.com', 'password3');

مثال: إدراج المنتجات

INSERT INTO products (name, description, price, stock, category)
VALUES
    ('Laptop', 'High-performance laptop', 899.99, 15, 'Electronics'),
    ('Mouse', 'Wireless mouse', 19.99, 50, 'Electronics'),
    ('Desk Chair', 'Ergonomic office chair', 199.99, 8, 'Furniture');

الحصول على آخر معرف تم إدراجه

-- في MySQL، بعد INSERT:
SELECT LAST_INSERT_ID();

-- في PHP (mysqli):
$last_id = $mysqli->insert_id;

-- في PHP (PDO):
$last_id = $pdo->lastInsertId();

اختيار البيانات باستخدام SELECT

عبارة SELECT تسترجع البيانات من جدول واحد أو أكثر.

اختيار جميع الأعمدة

SELECT * FROM users;

* تعني "جميع الأعمدة". المخرجات:

+----+----------+-------------------+------------------+---------------------+
| id | username | email             | password         | created_at          |
+----+----------+-------------------+------------------+---------------------+
| 1  | john_doe | john@example.com  | hashed_password  | 2024-01-15 10:30:00 |
| 2  | jane_doe | jane@example.com  | hashed_password  | 2024-01-15 11:45:00 |
+----+----------+-------------------+------------------+---------------------+

اختيار أعمدة محددة

SELECT username, email FROM users;

المخرجات:

+----------+-------------------+
| username | email             |
+----------+-------------------+
| john_doe | john@example.com  |
| jane_doe | jane@example.com  |
+----------+-------------------+

نصيحة للأداء: اختر فقط الأعمدة التي تحتاجها بدلاً من استخدام SELECT *. هذا يقلل نقل البيانات ويحسن الأداء، خاصة مع الجداول الكبيرة.

التصفية باستخدام WHERE

شرط WHERE يرشح النتائج بناءً على الشروط.

صيغة WHERE الأساسية

SELECT columns FROM table WHERE condition;

عوامل المقارنة

-- يساوي
SELECT * FROM products WHERE category = 'Electronics';

-- لا يساوي
SELECT * FROM products WHERE category != 'Electronics';
-- أو
SELECT * FROM products WHERE category <> 'Electronics';

-- أكبر من
SELECT * FROM products WHERE price > 100;

-- أصغر من
SELECT * FROM products WHERE stock < 10;

-- أكبر من أو يساوي
SELECT * FROM products WHERE price >= 50;

-- أصغر من أو يساوي
SELECT * FROM products WHERE stock <= 20;

العوامل المنطقية (AND, OR, NOT)

-- AND: يجب أن يكون كلا الشرطين صحيحين
SELECT * FROM products
WHERE category = 'Electronics' AND price < 500;

-- OR: يجب أن يكون شرط واحد على الأقل صحيحاً
SELECT * FROM products
WHERE category = 'Electronics' OR category = 'Furniture';

-- NOT: ينفي شرطاً
SELECT * FROM products
WHERE NOT category = 'Electronics';

-- دمج شروط متعددة
SELECT * FROM products
WHERE (category = 'Electronics' OR category = 'Furniture')
AND price BETWEEN 50 AND 500;

عامل BETWEEN

-- اختيار المنتجات بسعر بين 50 و 200
SELECT * FROM products
WHERE price BETWEEN 50 AND 200;

-- يعادل:
SELECT * FROM products
WHERE price >= 50 AND price <= 200;

عامل IN

-- اختيار المنتجات في فئات محددة
SELECT * FROM products
WHERE category IN ('Electronics', 'Furniture', 'Books');

-- يعادل:
SELECT * FROM products
WHERE category = 'Electronics'
   OR category = 'Furniture'
   OR category = 'Books';

عامل LIKE (مطابقة الأنماط)

-- % يطابق أي تسلسل من الأحرف
-- _ يطابق حرفاً واحداً بالضبط

-- المنتجات التي تبدأ بـ 'Lap'
SELECT * FROM products WHERE name LIKE 'Lap%';

-- المنتجات التي تنتهي بـ 'mouse'
SELECT * FROM products WHERE name LIKE '%mouse';

-- المنتجات التي تحتوي على 'chair'
SELECT * FROM products WHERE name LIKE '%chair%';

-- المنتجات التي تحتوي على 5 أحرف بالضبط
SELECT * FROM products WHERE name LIKE '_____';

-- غير حساس لحالة الأحرف افتراضياً في MySQL
SELECT * FROM users WHERE email LIKE '%@gmail.com';

قيم NULL

-- العثور على المنتجات بدون وصف
SELECT * FROM products WHERE description IS NULL;

-- العثور على المنتجات بوصف
SELECT * FROM products WHERE description IS NOT NULL;

-- ملاحظة: لا يمكنك استخدام = أو != مع NULL
-- خطأ: WHERE description = NULL
-- صحيح: WHERE description IS NULL

الترتيب باستخدام ORDER BY

شرط ORDER BY يرتب النتائج بترتيب تصاعدي (ASC) أو تنازلي (DESC).

الترتيب بعمود واحد

-- الترتيب حسب السعر (تصاعدي - الأقل أولاً)
SELECT * FROM products ORDER BY price ASC;

-- الترتيب حسب السعر (تنازلي - الأعلى أولاً)
SELECT * FROM products ORDER BY price DESC;

-- ASC افتراضي، لذا هذا يعادل:
SELECT * FROM products ORDER BY price;

الترتيب بأعمدة متعددة

-- الترتيب حسب الفئة، ثم حسب السعر ضمن كل فئة
SELECT * FROM products
ORDER BY category ASC, price DESC;

دمج WHERE و ORDER BY

SELECT name, price, stock
FROM products
WHERE category = 'Electronics' AND stock > 0
ORDER BY price DESC;

تحديد النتائج باستخدام LIMIT

شرط LIMIT يقيد عدد الصفوف المرجعة.

LIMIT الأساسي

-- الحصول على أول 5 منتجات
SELECT * FROM products LIMIT 5;

-- الحصول على 5 منتجات الأغلى
SELECT * FROM products
ORDER BY price DESC
LIMIT 5;

LIMIT مع OFFSET (الترقيم)

-- تخطي أول 10 صفوف، إرجاع التالية 5
SELECT * FROM products LIMIT 5 OFFSET 10;

-- صيغة بديلة (أقدم)
SELECT * FROM products LIMIT 10, 5;
-- LIMIT offset, count

-- مثال: الصفحة 1 (0-9)
SELECT * FROM products LIMIT 10 OFFSET 0;

-- الصفحة 2 (10-19)
SELECT * FROM products LIMIT 10 OFFSET 10;

-- الصفحة 3 (20-29)
SELECT * FROM products LIMIT 10 OFFSET 20;

صيغة الترقيم

-- الصيغة: LIMIT items_per_page OFFSET (page - 1) * items_per_page

-- الصفحة 1، 20 عنصر لكل صفحة:
SELECT * FROM products LIMIT 20 OFFSET 0;

-- الصفحة 3، 20 عنصر لكل صفحة:
SELECT * FROM products LIMIT 20 OFFSET 40;

دوال SELECT المفيدة

COUNT - عد الصفوف

-- عد جميع المنتجات
SELECT COUNT(*) FROM products;

-- عد المنتجات في فئة الإلكترونيات
SELECT COUNT(*) FROM products WHERE category = 'Electronics';

-- عد الأوصاف غير NULL
SELECT COUNT(description) FROM products;

SUM - حساب المجموع

-- القيمة الإجمالية لجميع المنتجات في المخزون
SELECT SUM(price * stock) AS total_inventory_value FROM products;

-- كمية المخزون الإجمالية
SELECT SUM(stock) FROM products;

AVG - حساب المتوسط

-- متوسط سعر المنتج
SELECT AVG(price) FROM products;

-- متوسط السعر في فئة الإلكترونيات
SELECT AVG(price) FROM products WHERE category = 'Electronics';

MIN و MAX

-- أرخص سعر منتج
SELECT MIN(price) FROM products;

-- أغلى سعر منتج
SELECT MAX(price) FROM products;

-- المنتج بأعلى سعر
SELECT * FROM products ORDER BY price DESC LIMIT 1;

DISTINCT - إزالة التكرارات

-- الحصول على الفئات الفريدة
SELECT DISTINCT category FROM products;

-- عد الفئات الفريدة
SELECT COUNT(DISTINCT category) FROM products;

أسماء مستعارة للأعمدة باستخدام AS

-- إعادة تسمية الأعمدة في المخرجات
SELECT
    name AS product_name,
    price AS cost,
    stock AS quantity_available
FROM products;

-- استخدام في الحسابات
SELECT
    name,
    price,
    stock,
    price * stock AS total_value
FROM products;

أمثلة عملية

مثال 1: بحث عن منتجات التجارة الإلكترونية

-- البحث عن أجهزة الكمبيوتر المحمولة بأقل من 1000 دولار، في المخزون، مرتبة حسب السعر
SELECT name, price, stock
FROM products
WHERE name LIKE '%laptop%'
  AND price < 1000
  AND stock > 0
ORDER BY price ASC;

مثال 2: تقرير تسجيل المستخدمين

-- الحصول على المستخدمين المسجلين في آخر 7 أيام
SELECT username, email, created_at
FROM users
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
ORDER BY created_at DESC;

مثال 3: تنبيه المخزون المنخفض

-- المنتجات بمخزون أقل من 10 وحدات
SELECT name, stock, category
FROM products
WHERE stock < 10 AND stock > 0
ORDER BY stock ASC;

مثال 4: لوحة تحكم المبيعات

-- إحصائيات ملخصة
SELECT
    COUNT(*) AS total_products,
    SUM(stock) AS total_items_in_stock,
    AVG(price) AS average_price,
    MIN(price) AS cheapest_product,
    MAX(price) AS most_expensive_product,
    SUM(price * stock) AS total_inventory_value
FROM products
WHERE is_active = 1;

تمرين: استعلامات كتالوج المنتجات

باستخدام جدول المنتجات، اكتب استعلامات SQL لما يلي:

  1. أدرج 3 منتجات جديدة في فئات مختلفة
  2. اختر جميع المنتجات مرتبة حسب السعر (الأعلى إلى الأقل)
  3. ابحث عن جميع المنتجات في فئة "الإلكترونيات" بسعر بين 50 و 500 دولار
  4. احصل على أحدث 10 منتجات مضافة
  5. عد عدد المنتجات في كل فئة
  6. ابحث عن المنتجات التي تحتوي أسماؤها على "pro" (غير حساس لحالة الأحرف)
  7. احسب القيمة الإجمالية لكل المخزون
  8. احصل على أغلى 5 منتجات الموجودة في المخزون

أفضل الممارسات

  • استخدم WHERE بحذر دائماً: الاستعلامات بدون WHERE يمكن أن تؤثر على جميع الصفوف عن طريق الخطأ
  • استخدم LIMIT: عند اختبار الاستعلامات، أضف LIMIT لتجنب النتائج الطويلة
  • فهرس الأعمدة المبحوث عنها بشكل متكرر: أضف فهارس على الأعمدة المستخدمة في WHERE و ORDER BY و JOIN
  • استخدم أسماء أعمدة محددة: تجنب SELECT * في كود الإنتاج
  • نظّف مدخلات المستخدم: لا تضع مدخلات المستخدم مباشرة في SQL (يمنع حقن SQL)
  • استخدم العبارات المحضرة: في PHP، استخدم عبارات PDO أو mysqli المحضرة

تحذير حقن SQL

لا تقم أبداً ببناء استعلامات SQL عن طريق دمج مدخلات المستخدم:

// خطير - لا تفعل هذا أبداً!
$query = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "'";

// آمن - استخدم العبارات المحضرة (سنغطيها في دروس لاحقة)
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$_POST['username']]);

ترتيب تنفيذ الاستعلام

شروط SQL تُكتب بهذا الترتيب:

  1. SELECT - الأعمدة المراد إرجاعها
  2. FROM - الجدول المراد الاستعلام عنه
  3. WHERE - تصفية الصفوف
  4. GROUP BY - تجميع الصفوف (سنغطيه لاحقاً)
  5. HAVING - تصفية المجموعات (سنغطيه لاحقاً)
  6. ORDER BY - ترتيب النتائج
  7. LIMIT - تقييد عدد الصفوف

لكن MySQL ينفذها بترتيب مختلف: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT

ما التالي؟

في الدرس التالي، ستتعلم كيفية تعديل البيانات الموجودة باستخدام UPDATE وإزالة البيانات باستخدام عبارات DELETE، إلى جانب ممارسات السلامة المهمة.