تخطَّ إلى المحتوى

العروض في MySQL: CREATE VIEW مع IF و CASE

الدرس 11 من 12 · MySQL

استعلام «تفاصيل الطلبات» في متجرنا يربط ثلاثة جداول ويحسب الإجمالي. هل ستكتبه من جديد في كل صفحة وكل تقرير؟ وماذا لو تغيّرت طريقة الحساب؟ العرض (View) يحل المشكلة: استعلام محفوظ باسم، تتعامل معه كأنه جدول. في هذا الدرس ستتعلم إنشاء العروض، ومعها IF و CASE لإضافة أعمدة محسوبة مفيدة.

IF و CASE: أعمدة بمنطق شرطي

Section titled “IF و CASE: أعمدة بمنطق شرطي”

قبل العروض، نحتاج أداتين. الدالة IF خاصة بـ MySQL وتأخذ شرطاً وقيمتين:

SELECT name, price, IF(price > 200, 'غالٍ', 'عادي') AS level FROM products;

الناتج:

name price level
كتاب البرمجة للمبتدئين 108.00 عادي
سماعة لاسلكية 450.50 غالٍ
حقيبة مدرسية 280.00 غالٍ
آلة حاسبة علمية 199.99 عادي
قصص الأطفال 58.50 عادي
مجموعة أقلام 35.75 عادي

IF(شرط, قيمة إذا تحقق, قيمة إذا لم يتحقق). ولأكثر من حالتين نستخدم CASE القياسية، وهي تفحص الشروط بالترتيب وتُرجع قيمة أول شرط يتحقق:

SELECT name, stock,
CASE
WHEN stock = 0 THEN 'غير متوفر'
WHEN stock < 10 THEN 'كمية محدودة'
ELSE 'متوفر'
END AS status
FROM products;

الناتج:

name stock status
كتاب البرمجة للمبتدئين 15 متوفر
سماعة لاسلكية 7 كمية محدودة
حقيبة مدرسية 0 غير متوفر
آلة حاسبة علمية 20 متوفر
قصص الأطفال 30 متوفر
مجموعة أقلام 50 متوفر

هذه هي الشارة التي تراها تحت كل منتج في أي متجر إلكتروني.

قاعدة «متى نقول كمية محدودة؟» ستحتاجها صفحة المنتج، ولوحة التحكم، وتقرير المخزون. بدل نسخ CASE في كل مكان، احفظها مرة واحدة:

CREATE VIEW product_status AS
SELECT id, name, price, stock,
CASE
WHEN stock = 0 THEN 'غير متوفر'
WHEN stock < 10 THEN 'كمية محدودة'
ELSE 'متوفر'
END AS status
FROM products;

والآن استعلم منه كأي جدول:

SELECT name, status FROM product_status WHERE status <> 'متوفر';

الناتج:

name status
سماعة لاسلكية كمية محدودة
حقيبة مدرسية غير متوفر

لاحظ أننا صفّينا بالعمود المحسوب status مباشرة، وهذا غير ممكن في الاستعلام الأصلي دون تكرار CASE في WHERE. ويعمل معه التجميع أيضاً:

SELECT status, COUNT(*) AS items FROM product_status GROUP BY status;

الناتج:

status items
غير متوفر 1
كمية محدودة 1
متوفر 4

العرض مثل نافذة على الجداول: لا يخزن بيانات، بل يريك البيانات الأصلية من زاوية معيّنة.

لأن العرض لا يخزن شيئاً، فهو يعكس أي تغيير في الجدول الأصلي فوراً. جرّبنا داخل معاملة تصفير مخزون الأقلام:

START TRANSACTION;
UPDATE products SET stock = 0 WHERE id = 6;
SELECT name, stock, status FROM product_status WHERE id = 6;

الناتج:

name stock status
مجموعة أقلام 0 غير متوفر

تغيّرت الحالة في العرض تلقائياً. وبعد ROLLBACK; عاد المخزون 50 والحالة «متوفر». في كل مرة تستعلم من العرض، تنفّذ MySQL استعلامه الأصلي من جديد.

هنا الفائدة الأكبر: إخفاء JOIN معقد خلف اسم بسيط.

CREATE VIEW order_details AS
SELECT o.id AS order_id, c.name AS customer, p.name AS product,
o.quantity, o.quantity * p.price AS total, o.order_date
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN products p ON p.id = o.product_id;
SELECT customer, product, total FROM order_details
WHERE order_date >= '2026-11-01';

الناتج:

customer product total
سارة مجموعة أقلام 71.50
عمر كتاب البرمجة للمبتدئين 108.00

وتقرير «كبار العملاء» أصبح سطرين بلا أي ربط ظاهر:

SELECT customer, COUNT(*) AS orders_count, SUM(total) AS spent
FROM order_details
GROUP BY customer
ORDER BY spent DESC;

الناتج:

customer orders_count spent
عمر 2 1009.00
سارة 3 379.49

وإذا تغيّرت طريقة حساب الإجمالي غداً (ضريبة أو خصم مثلاً)، تعدّل العرض فقط، وكل الاستعلامات التي تستخدمه تأخذ الحساب الجديد.

SHOW FULL TABLES;

الناتج:

Tables_in_shop Table_type
customers BASE TABLE
order_details VIEW
orders BASE TABLE
product_status VIEW
products BASE TABLE
subscribers BASE TABLE

العروض تظهر مع الجداول، والعمود Table_type يفرّق بينهما. ولهذا لا يمكن أن يحمل عرض وجدول الاسم نفسه. ولرؤية الاستعلام المحفوظ داخل عرض: SHOW CREATE VIEW product_status;.

CREATE OR REPLACE VIEW تنشئ العرض أو تستبدل تعريفه إن كان موجوداً. هنا نضيف عمود التصنيف:

CREATE OR REPLACE VIEW product_status AS
SELECT id, name, category, price, stock,
CASE
WHEN stock = 0 THEN 'غير متوفر'
WHEN stock < 10 THEN 'كمية محدودة'
ELSE 'متوفر'
END AS status
FROM products;

والحذف بـ DROP VIEW product_status;. حذف العرض لا يحذف أي بيانات، فالبيانات في الجداول الأصلية.

هل يمكن التعديل عبر العرض؟

Section titled “هل يمكن التعديل عبر العرض؟”

العرض البسيط المبني على جدول واحد دون تجميع قابل للتعديل: UPDATE عليه يغيّر الجدول الأصلي. أنشأنا عرضاً للمنتجات الأرخص من 100 وجرّبنا داخل معاملة:

CREATE VIEW cheap_products AS
SELECT id, name, price FROM products WHERE price < 100;
UPDATE cheap_products SET price = 40 WHERE id = 6;

فأصبح سعر الأقلام في جدول products نفسه 40.00 (ثم تراجعنا). أما الأعمدة المحسوبة فلا يمكن تعديلها:

UPDATE order_details SET total = 0 WHERE order_id = 1;

الناتج: ERROR 1348 (HY000): Column 'total' is not updatable

وهذا منطقي: total ناتج ضرب، فأي الطرفين ستغيّر MySQL؟ والعروض التي فيها GROUP BY أو DISTINCT أو دوال تجميع للقراءة فقط كلها.

  1. أنشئ عرضاً books يعرض اسم وسعر المنتجات التي تصنيفها «كتب» فقط.
  2. أنشئ عرضاً products_with_tax فيه الاسم والسعر وعمود with_tax يساوي السعر مضروباً في 1.14.
  3. استخدم العرض order_details لمعرفة المنتج الأكثر مبيعاً (مجموع الكميات).
  4. تحدٍّ: أنشئ عرضاً customer_summary يعرض لكل عميل عدد طلباته، مع LEFT JOIN حتى يظهر كريم بصفر، وعمود kind قيمته «نشط» أو «جديد» باستخدام IF.
  • اسم مستخدَم: إنشاء عرض باسم موجود يعطي ERROR 1050 (42S01): Table 'cheap_products' already exists. استخدم CREATE OR REPLACE VIEW.
  • الظن بأن العرض أسرع: العرض لا يخزن النتيجة، بل ينفّذ استعلامه في كل مرة. هو يبسّط الكود ولا يسرّعه.
  • حذف عمود يعتمد عليه عرض: يبقى العرض موجوداً لكنه يعطي خطأ عند استخدامه. راجع العروض قبل تعديل بنية الجداول.
  • عروض فوق عروض فوق عروض: تصعب معرفة ما يحدث فعلاً ويبطؤ الأداء. اجعلها طبقة واحدة أو اثنتين.

سؤال

ماذا يخزن العرض View في قاعدة البيانات؟

سؤال

ما ناتج IF(5 > 3, 'نعم', 'لا')؟

  • IF(شرط, أ, ب) لحالتين، و CASE WHEN ... END لعدة حالات.
  • CREATE VIEW name AS SELECT ... يحفظ الاستعلام باسم يُستخدم كجدول.
  • العرض لا يخزن بيانات: يعكس التغييرات فوراً ويُنفَّذ عند كل استخدام.
  • العروض تخفي الربط والحسابات المعقدة وتوحّدها في مكان واحد.
  • العرض البسيط قابل للتعديل، والأعمدة المحسوبة والعروض التجميعية للقراءة فقط.