استخدام Having في MySQL: الدليل الكامل

آخر تحديث: 24 في مايو 2025
نبذة عن الكاتب: تكنوديجيتال
  • تقوم عبارة Having بتصفية مجموعات الصفوف بعد التجميع باستخدام GROUP BY.
  • يتيح لك تطبيق الشروط على وظائف التجميع للحصول على نتائج دقيقة.
  • يؤدي تحسين الاستعلامات باستخدام الفهارس والأقسام إلى تحسين الأداء.
  • تساعد الأدوات مثل EXPLAIN في تحليل الاستعلامات وتصحيح أخطائها.
وجود في mysql

هل تريد أن تتعلم كيفية استخدام شرط Have في MySQL لتحسين استعلاماتك والحصول على نتائج أكثر دقة؟ هل تبحث عن طريقة لرفع مهاراتك في قواعد البيانات إلى المستوى التالي؟ لقد وصلت إلى المكان الصحيح!

سنعرض لك هنا طرقًا فعالة لتحقيق أقصى استفادة من هذه الأداة القوية. تعتبر عبارة Having ميزة أساسية في MySQL تتيح لك تصفية البيانات المجمعة وتحليلها بكفاءة. باستخدام Having، يمكنك تطبيق شروط معقدة على نتائج استعلامك، مما يتيح لك التحكم الدقيق في المعلومات التي تريد استردادها.

تخيل أن لديك قاعدة بيانات للمبيعات وأنك بحاجة إلى الحصول على رؤى قيمة حول أداء منتجاتك أو تقسيم عملائك. باستخدام البند Having، يمكنك تجميع بياناتك حسب معايير محددة ثم تصفية هذه المجموعات للحصول على نتائج أكثر فائدة. على سبيل المثال، يمكنك الحصول على فئات المنتجات التي حققت مبيعات إجمالية تتجاوز حدًا معينًا، أو تحديد العملاء الذين قاموا بعدد أدنى من المشتريات خلال فترة زمنية معينة.

مقدمة إلى البند Having في MySQL

تخيل أن لديك قاعدة بيانات للمبيعات وتريد الحصول على معلومات حول المنتجات التي حققت مبيعات إجمالية تتجاوز حدًا معينًا. وهنا يأتي دور شرط "الحصول". يمكنك تجميع المبيعات حسب المنتج ثم استخدام ميزة "الاضطرار" لتصفية المنتجات التي يتجاوز مجموع مبيعاتها الحد المطلوب فقط.

SELECT columna1, columna2, ..., función_agregado(columna)
FROM tabla
GROUP BY columna1, columna2, ...
HAVING condición;

الفرق بين WHERE وHAVING

SELECT categoria, SUM(ventas) AS total_ventas
FROM productos
WHERE precio > 100
GROUP BY categoria
HAVING SUM(ventas) > 1000;

فيما يلي بعض القواعد العامة لتحديد متى نستخدم WHERE أو Having :

  • استخدم WHERE لتصفية الصفوف الفردية قبل التجميع.
  • استخدام ضرورة تصفية مجموعات الصفوف بعد التجميع.
  • لا يمكن لـ WHERE الإشارة إلى وظائف التجميع، بينما يمكن لـ Having الإشارة إليها.
  • يمكنك استخدام WHERE وHave في نفس الاستعلام إذا لزم الأمر.

إن فهم الفرق بين WHERE وHave سوف يمكّنك من كتابة استعلامات أكثر دقة وكفاءة، والاستفادة الكاملة من إمكانيات التصفية في MySQL.

الاستخدام الأساسي لـHaving

SELECT columna1, columna2, ..., función_agregado(columna)
FROM tabla
GROUP BY columna1, columna2, ...
HAVING condición;
SELECT id_producto, SUM(cantidad) AS total_vendido
FROM ventas
GROUP BY id_producto
HAVING SUM(cantidad) > 100;
SELECT id_producto, SUM(cantidad) AS total_vendido
FROM ventas
GROUP BY id_producto
HAVING SUM(cantidad) > 100 AND SUM(cantidad) < 500;

الجمع بين Have مع وظائف التجميع

  • مجموع:يحسب مجموع القيم في عمود.
  • بالإحصاء:يحسب عدد الصفوف أو القيم غير الفارغة في عمود.
  • AVG:يحسب متوسط ​​القيم في عمود.
  • وفر:إرجاع الحد الأقصى للقيمة في عمود.
  • دقيقة:إرجاع الحد الأدنى لقيمة العمود.
  1. احصل على العملاء الذين يبلغ متوسط ​​مشترياتهم أكثر من 100 دولار:
SELECT id_cliente, AVG(total) AS promedio_compras
FROM pedidos
GROUP BY id_cliente
HAVING AVG(total) > 100;
  1. احسب عدد الطلبات لكل عميل وأظهر فقط تلك التي تحتوي على أكثر من 5 طلبات:
SELECT id_cliente, COUNT(*) AS total_pedidos
FROM pedidos
GROUP BY id_cliente
HAVING COUNT(*) > 5;
  1. احصل على المنتجات التي يكون الحد الأقصى لسعرها أقل من 50 دولارًا:
SELECT id_producto, MAX(precio) AS precio_maximo
FROM productos
GROUP BY id_producto
HAVING MAX(precio) < 50;
  1. عرض فئات المنتجات التي يبلغ إجمالي مبيعاتها أكثر من 10,000 دولار:
SELECT categoria, SUM(total) AS total_ventas
FROM ventas
GROUP BY categoria
HAVING SUM(total) > 10000;
SELECT categoria, SUM(total) AS total_ventas, AVG(precio) AS precio_promedio
FROM ventas
GROUP BY categoria
HAVING SUM(total) > 10000 AND AVG(precio) < 50;

التصفية الشرطية باستخدام Have

  • الحالات:يسمح لك بإنشاء تعبيرات شرطية تحتوي على شروط ونتائج متعددة.
  • IF:يقوم بتقييم الشرط وإرجاع قيمة واحدة إذا تم استيفاؤه وقيمة أخرى إذا لم يتم استيفاؤه.
  • المعاملات المنطقية (AND، OR، NOT): دمج شروط متعددة لإنشاء تعبيرات منطقية أكثر تعقيدًا.
  1. احصل على فئات المنتجات التي يبلغ إجمالي مبيعاتها أكثر من 10,000 فقط للمنتجات التي يزيد سعرها عن 50:
SELECT categoria, SUM(total_ventas) AS total_ventas
FROM ventas
WHERE precio > 50
GROUP BY categoria
HAVING SUM(total_ventas) > 10000;
  1. عرض العملاء الذين بلغ متوسط ​​مبلغ مشترياتهم أكثر من 100 دولار لأولئك الذين قدموا أكثر من 5 طلبات:
SELECT id_cliente, AVG(total) AS promedio_compras
FROM pedidos
GROUP BY id_cliente
HAVING AVG(total) > 100 AND COUNT(*) > 5;
  1. احصل على فئات المنتجات التي يبلغ إجمالي مبيعاتها أكثر من 10,000 وقم بتصنيفها على أنها "عالية" إذا كان الإجمالي أكبر من 50,000، و"متوسطة" إذا كان بين 20,000 و50,000، و"منخفضة" بخلاف ذلك:
SELECT 
    categoria,
    SUM(total_ventas) AS total_ventas,
    CASE 
        WHEN SUM(total_ventas) > 50000 THEN 'Alto'
        WHEN SUM(total_ventas) BETWEEN 20000 AND 50000 THEN 'Medio'
        ELSE 'Bajo'
    END AS clasificacion
FROM ventas
GROUP BY categoria
HAVING SUM(total_ventas) > 10000;
  1. إظهار المنتجات التي يزيد متوسط ​​سعرها عن 100 دولار فقط إذا كانت قد حققت مبيعات خلال الثلاثين يومًا الماضية:
SELECT 
    id_producto,
    AVG(precio) AS precio_promedio
FROM ventas
WHERE fecha >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY id_producto
HAVING AVG(precio) > 100;
SELECT 
    categoria,
    SUM(total) AS total_ventas
FROM ventas
GROUP BY categoria
HAVING SUM(total) > (
    SELECT AVG(total_ventas)
    FROM (
        SELECT categoria, SUM(total) AS total_ventas
        FROM ventas
        GROUP BY categoria
    ) AS subconsulta
);

أمثلة عملية للاستعلامات التي تحتوي على

  1. احصل على الأقسام التي تضم أكثر من 5 موظفين واعرض متوسط ​​الراتب لكل قسم:
SELECT 
    departamento,
    COUNT(*) AS total_empleados,
    AVG(salario) AS salario_promedio
FROM empleados
GROUP BY departamento
HAVING COUNT(*) > 5;
  1. عرض فئات المنتجات التي يبلغ إجمالي مبيعاتها أكثر من 10,000 دولار وهامش ربح أكبر من 20%:
SELECT 
    categoria,
    SUM(total) AS total_ventas,
    (SUM(total) - SUM(costo)) / SUM(total) AS margen_ganancia
FROM ventas
GROUP BY categoria
HAVING 
    SUM(total) > 10000 
    AND (SUM(total) - SUM(costo)) / SUM(total) > 0.2;
  1. احصل على العملاء الذين قاموا بعمليات شراء في 3 فئات مختلفة على الأقل وكان إجمالي مشترياتهم أكبر من 1,000 دولار:
SELECT 
    id_cliente,
    COUNT(DISTINCT categoria) AS total_categorias,
    SUM(total) AS total_compras
FROM ventas
GROUP BY id_cliente
HAVING 
    COUNT(DISTINCT categoria) >= 3 
    AND SUM(total) > 1000;
  1. إظهار المنتجات التي يبلغ متوسط ​​تقييمها أكثر من 4.5 والتي حصلت على 10 تقييمات على الأقل:
SELECT 
    id_producto,
    AVG(calificacion) AS promedio_calificacion,
    COUNT(*) AS total_calificaciones
FROM calificaciones
GROUP BY id_producto
HAVING 
    AVG(calificacion) > 4.5 
    AND COUNT(*) >= 10;
  1. احصل على المتاجر التي حققت إجمالي مبيعات أعلى من متوسط ​​مبيعات جميع المتاجر في آخر 30 يومًا:
SELECT 
    id_tienda,
    SUM(total) AS total_ventas
FROM ventas
WHERE fecha >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP BY id_tienda
HAVING 
    SUM(total) > (
        SELECT AVG(total_ventas)
        FROM (
            SELECT id_tienda, SUM(total) AS total_ventas
            FROM ventas
            WHERE fecha >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
            GROUP BY id_tienda
        ) AS subconsulta
    );
تجميع حسب mysql مع الأمثلة
مقالة ذات صلة:
جملة GROUP BY في MySQL مع الأمثلة

تحسين الأداء باستخدام MySQL

  1. استخدم الفهارس المناسبة:
    • تأكد من وجود فهارس على الأعمدة المستخدمة في البند GROUP BY وفي الأعمدة الداخلة في شروط جملة الشرط.
    • يمكن أن تعمل الفهارس على تحسين الأداء بشكل كبير عن طريق تقليل كمية البيانات التي يجب على MySQL فحصها لأداء التجميع.
  2. تجنب الحسابات غير الضرورية في وجود:
    • إذا كان ذلك ممكنًا، فحاول إجراء العمليات الحسابية والتصفية في شرط WHERE قبل التجميع.
    • قد يؤدي تصفية الصفوف الفردية قبل التجميع إلى تقليل كمية البيانات التي تتم معالجتها في شرط Having، مما يحسن الأداء.
  3. استخدم الاستعلامات الفرعية أو الجداول المؤقتة:
    • في بعض الحالات، قد يكون من الأكثر كفاءة استخدام الاستعلامات الفرعية أو الجداول المؤقتة لإجراء حسابات وسيطة قبل تطبيق شرط Have.
    • يمكن أن يؤدي هذا إلى تجنب الحاجة إلى الحسابات المتكررة وتقليل تعقيد الاستعلام الرئيسي.
  4. تحسين وظائف التجميع:
    • استخدم وظائف التجميع المناسبة لاحتياجاتك. على سبيل المثال، إذا كنت تحتاج فقط إلى حساب عدد الصفوف، استخدم COUNT(*) بدلاً من COUNT(column).
    • تجنب استخدام وظائف التجميع غير الضرورية أو المكررة في البند Having.
  5. تحديد عدد المجموعات:
    • إذا كان ذلك ممكنًا، فحاول تحديد عدد المجموعات التي تم إنشاؤها بواسطة عبارة GROUP BY.
    • كلما تم إنشاء مجموعات أقل، كلما قل عدد الحسابات والمقارنات التي يتم إجراؤها في بند Have، مما يؤدي إلى تحسين الأداء.
  6. استخدم EXPLAIN لتحليل خطة التنفيذ:
    • استخدم عبارة EXPLAIN قبل الاستعلام الخاص بك للحصول على معلومات حول كيفية تخطيط MySQL لتنفيذه.
    • قم بتحليل خطة التنفيذ لتحديد الاختناقات المحتملة أو مجالات التحسين، مثل الفهارس المفقودة أو الاستخدام غير الفعال للموارد.
  7. خذ بعين الاعتبار استخدام الأقسام:
    • إذا كنت تعمل مع جداول كبيرة جدًا، ففكر في استخدام أقسام لتقسيم البيانات إلى أجزاء أصغر وأكثر قابلية للإدارة.
    • يمكن للأقسام تحسين الأداء من خلال السماح لـ MySQL بالوصول إلى الأقسام ذات الصلة باستعلام معين ومعالجتها فقط.
  ما هي قواعد البيانات غير العلائقية؟

وجود بالاشتراك مع JOIN

  1. احصل على العملاء الذين قاموا بعمليات شراء في جميع فئات المنتجات:
SELECT 
    c.id_cliente,
    c.nombre,
    COUNT(DISTINCT v.categoria) AS total_categorias
FROM clientes c
JOIN ventas v ON c.id_cliente = v.id_cliente
GROUP BY c.id_cliente, c.nombre
HAVING COUNT(DISTINCT v.categoria) = (
    SELECT COUNT(DISTINCT categoria) FROM productos
);
  1. عرض أزواج المنتجات التي تم بيعها معًا في 10 طلبات على الأقل:
SELECT 
    v1.id_producto AS producto1,
    v2.id_producto AS producto2,
    COUNT(*) AS total_ordenes
FROM ventas v1
JOIN ventas v2 ON v1.id_orden = v2.id_orden AND v1.id_producto < v2.id_producto
GROUP BY v1.id_producto, v2.id_producto
HAVING COUNT(*) >= 10;
  1. احصل على فئات المنتجات التي يبلغ إجمالي مبيعاتها أعلى من متوسط ​​مبيعات جميع الفئات، مع مراعاة المبيعات خلال الأشهر الستة الماضية فقط:
SELECT 
    p.categoria,
    SUM(v.total) AS total_ventas
FROM productos p
JOIN ventas v ON p.id_producto = v.id_producto
WHERE v.fecha >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH)
GROUP BY p.categoria
HAVING SUM(v.total) > (
    SELECT AVG(total_ventas)
    FROM (
        SELECT p.categoria, SUM(v.total) AS total_ventas
        FROM productos p
        JOIN ventas v ON p.id_producto = v.id_producto
        WHERE v.fecha >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH)
        GROUP BY p.categoria
    ) AS subconsulta
);

الأخطاء الشائعة عند استخدام having وكيفية تجنبها

  1. استخدام الأعمدة غير المجمعة في البند Having دون تضمينها في GROUP BY:
    • خطأ: إذا حاولت الإشارة إلى عمود غير مجمع في البند Having دون تضمينه في البند GROUP BY، فسوف تتلقى خطأ.
    • الحل: تأكد من تضمين جميع الأعمدة غير المجمعة المذكورة في البند Having في البند GROUP BY.
  2. الخلط بين WHERE وHave الشروط:
    • خطأ: وضع شروط التصفية في البند Having الذي يجب أن يكون في البند WHERE، أو العكس.
    • الحل: تذكر أن شرط WHERE يتم تطبيقه قبل التجميع ويتم استخدامه لتصفية الصفوف الفردية، بينما يتم تطبيق شرط Have بعد التجميع ويتم استخدامه لتصفية مجموعات من الصفوف.
  3. نسيان تضمين شرط GROUP BY:
    • خطأ: إذا استخدمت وظائف التجميع في استعلامك دون تحديد شرط GROUP BY، فسوف تتلقى خطأ.
    • الحل: تأكد من تضمين شرط GROUP BY وتحديد الأعمدة التي تريد تجميع النتائج حسبها.
  4. استخدام وظائف التجميع في شرط WHERE:
    • خطأ: لا يمكن استخدام الدوال التجميعية مثل SUM، وCOUNT، وAVG، وMAX، وMIN، وما إلى ذلك، بشكل مباشر في البند WHERE.
    • الحل: إذا كنت بحاجة إلى تصفية النتائج استنادًا إلى نتيجة دالة تجميعية، فاستخدم استعلامًا فرعيًا أو انقل الشرط إلى شرط Have.
  5. عدم التعامل بشكل صحيح مع القيم الفارغة:
    • خطأ: تتعامل الدوال التجميعية مع القيم الفارغة بشكل مختلف، مما قد يؤدي إلى نتائج غير متوقعة إذا لم يتم التعامل معها بشكل صحيح.
    • الحل: استخدم وظائف مثل COUNT(*) بدلاً من COUNT(column) إذا كنت تريد تضمين الصفوف ذات القيم الفارغة في العدد. فكر في استخدام وظائف مثل COALESCE أو IFNULL للتعامل مع القيم الفارغة بشكل مناسب.
  6. Rأداء ضعيف بسبب الفهارس المفقودة أو الاستعلامات غير المحسّنة بشكل جيد:
  • خطأ: يمكن أن تصبح الاستعلامات التي تستخدم Having بطيئة إذا لم يتم استخدام الفهارس المناسبة أو إذا تم إجراء حسابات غير ضرورية.
  • الحل: تأكد من وجود فهارس على الأعمدة المستخدمة في جملة GROUP BY وعلى الأعمدة المشاركة في الشروط في جملة Have. قم بتحسين الاستعلامات عن طريق تجنب الحسابات غير الضرورية واستخدام الاستعلامات الفرعية أو الجداول المؤقتة عند الحاجة.
  1. عدم مراعاة ترتيب البنود:
    • خطأ: وضع البنود بالترتيب الخاطئ يمكن أن يؤدي إلى أخطاء في بناء الجملة أو نتائج غير متوقعة.
    • الحل: تأكد من اتباع الترتيب الصحيح للجمل: SELECT، FROM، WHERE، GROUP BY، HAVING، ORDER BY.
  2. استخدام الشروط الغامضة أو غير الواضحة في جملة Have:
    • الخطأ: كتابة شروط معقدة أو غير واضحة في البند Having قد يجعل من الصعب فهم الكود الخاص بك وصيانته.
    • الحل: اكتب شروطًا واضحة وموجزة في جملة Have. إذا كانت الشروط معقدة للغاية، ففكر في تقسيم الاستعلام إلى عدة استعلامات أبسط أو استخدام الاستعلامات الفرعية لتحسين قابلية القراءة.
  3. عدم اختبار الاستعلامات بشكل شامل باستخدام مجموعات بيانات مختلفة:
    • خطأ: قد تعمل الاستعلامات التي تستخدم Have بشكل صحيح مع مجموعة بيانات اختبار ولكنها تفشل أو تنتج نتائج غير صحيحة مع بيانات حقيقية أو أكبر.
    • الحل: اختبار الاستعلامات بشكل شامل باستخدام مجموعات بيانات مختلفة، بما في ذلك الحالات الحدية وسيناريوهات البيانات المفقودة أو الخالية. استخدم أدوات تحليل الأداء وتصحيح الأخطاء لتحديد المشكلات واستكشاف الأخطاء وإصلاحها.
  4. عدم توثيق الاستعلامات المعقدة بشكل صحيح:
    • خطأ: عدم وجود توثيق أو تعليقات على الاستعلامات المعقدة مع Have يمكن أن يجعل من الصعب فهمها وصيانتها بواسطة مطورين آخرين أو نفسك في المستقبل.
    • الحل: أضف تعليقات واضحة وموجزة تشرح غرض كل جزء من الاستعلام، وخاصة في شروط جملة Have. توثيق أي منطق معقد أو متطلبات عمل محددة.

بدائل لـ Have في حالات محددة

  1. الاستعلامات الفرعية:
    • بدلاً من استخدام تصفية النتائج المجمعة، يمكنك استخدم الاستعلامات الفرعية لإجراء الحسابات والتصفية اللازمة قبل التجميع.
    • يمكن أن تكون الاستعلامات الفرعية مفيدة بشكل خاص عندما تحتاج إلى مقارنة القيم المجمعة مع القيم المحسوبة في استعلام منفصل.
    • على سبيل المثال:
       SELECT *
      FROM (
          SELECT categoria, SUM(total) AS total_ventas
          FROM ventas
          GROUP BY categoria
      ) AS subconsulta
      WHERE total_ventas > 10000;
      
  2. المشاهدات:
    • إذا كان لديك استعلام معقد مع استخدام Having بشكل متكرر، فيمكنك إنشاء عرض في MySQL الذي يغلف منطق الاستعلام.
    • توفر العروض طريقة لتبسيط وإعادة استخدام الاستعلامات المعقدة، ويمكنها تحسين قابلية قراءة التعليمات البرمجية وإمكانية صيانتها.
    • على سبيل المثال:
       CREATE VIEW ventas_por_categoria AS
      CREATE VIEW ventas_por_categoria AS
      SELECT categoria, SUM(total) AS total_ventas
      FROM ventas
      GROUP BY categoria;
      
      SELECT *
      FROM ventas_por_categoria
      WHERE total_ventas > 10000;
      
  3. الجداول المشتقة:
    • على غرار الاستعلامات الفرعية، تسمح لك الجداول المشتقة بإجراء العمليات الحسابية والتصفية في استعلام داخلي ثم استخدام النتائج في الاستعلام الرئيسي.
    • يمكن أن تكون الجداول المشتقة مفيدة عندما تحتاج إلى تنفيذ عمليات تجميع متعددة أو تصفية معقدة قبل دمج النتائج مع جداول أخرى.
    • على سبيل المثال:
       SELECT c.nombre, v.total_ventas
      FROM clientes c
      JOIN (
          SELECT id_cliente, SUM(total) AS total_ventas
          FROM ventas
          GROUP BY id_cliente
      ) AS v ON c.id_cliente = v.id_cliente
      WHERE v.total_ventas > 1000;
      
  4. وظائف النافذة:
    • يمكن استخدام وظائف النافذة مثل ROW_NUMBER() وRANK() وDENSE_RANK() وما إلى ذلك لإجراء الحسابات والتصفية استنادًا إلى أقسام البيانات دون استخدام Have.
    • تُعد وظائف النافذة مفيدة بشكل خاص عندما تحتاج إلى إجراء حسابات استنادًا إلى مجموعات من الصفوف ذات الصلة وتصفية النتائج استنادًا إلى تلك الحسابات.
    • على سبيل المثال:
       SELECT *
      FROM (
          SELECT categoria, total, 
                 ROW_NUMBER() OVER (PARTITION BY categoria ORDER BY total DESC) AS rn
          FROM ventas
      ) AS subconsulta
      WHERE rn <= 3;
      

مع البيانات الفارغة والقيم الافتراضية

  1. الوظائف التجميعية والقيم الفارغة:
    • تتعامل الدوال التجميعية، مثل SUM، وAVG، وCOUNT، وما إلى ذلك، مع القيم الصفرية بشكل مختلف اعتمادًا على الدالة المحددة.
    • يتضمن COUNT(*) جميع الصفوف في العد، حتى الصفوف التي تحتوي على قيم فارغة في جميع الأعمدة.
    • يقوم COUNT(column) فقط بحساب الصفوف التي لا يحتوي العمود المحدد فيها على قيمة فارغة.
    • يتجاهل SUM وAVG القيم الفارغة ويعملان فقط على القيم غير الفارغة.
    • على سبيل المثال:
       SELECT departamento, COUNT(*) AS total_empleados, AVG(salario) AS salario_promedio
      FROM empleados
      GROUP BY departamento
      HAVING AVG(salario) > 5000;
      
  2. التعامل مع القيم الفارغة باستخدام COALESCE أو IFNULL:
    • إذا كان لديك أعمدة قد تحتوي على قيم فارغة وتريد تضمينها في الحسابات أو الشروط، فيمكنك استخدام الدالتين COALESCE أو IFNULL لتوفير قيمة افتراضية.
    • تقوم COALESCE(column, default_value) بإرجاع أول قيمة غير فارغة في قائمة الوسائط.
    • تقوم IFNULL(column, default_value) بإرجاع القيمة الافتراضية المحددة إذا كان العمود فارغًا.
    • على سبيل المثال:
       SELECT departamento, AVG(COALESCE(salario, 0)) AS salario_promedio
      FROM empleados
      GROUP BY departamento
      HAVING AVG(COALESCE(salario, 0)) > 5000;
      
  3. تصفية المجموعات ذات القيم الفارغة:
    • إذا كنت تريد تصفية المجموعات بناءً على وجود أو عدم وجود قيم فارغة في عمود معين، فيمكنك استخدام الشرطين IS NULL أو IS NOT NULL في البند Have.
    • على سبيل المثال:
       SELECT departamento, COUNT(*) AS total_empleados
      FROM empleados
      GROUP BY departamento
      HAVING MAX(salario) IS NULL;
      
  4. القيم الافتراضية في الشروط التالية:
    • عند مقارنة نتائج الدوال التجميعية مع القيم الافتراضية في شرط Have، كن حذرًا مع منطق الشرط.
    • تأكد من أن القيم الافتراضية المستخدمة تتوافق مع منطق الشرط وتوفر النتائج المتوقعة.
    • على سبيل المثال:
       SELECT departamento, AVG(COALESCE(salario, 0)) AS salario_promedio
      FROM empleados
      GROUP BY departamento
      HAVING AVG(COALESCE(salario, 0)) > 0;
      
  5. اعتبارات الأداء مع القيم الصفرية:
    • إن التعامل مع القيم الفارغة في وظائف التجميع ووجود الشروط قد يؤثر على أداء الاستعلام، وخاصةً على مجموعات البيانات الكبيرة.
    • إذا كان لديك عدد كبير من القيم الفارغة في الأعمدة المستخدمة في وظائف التجميع، ففكر في استخدام الفهارس الجزئية أو استراتيجيات التصفية المسبقة لتحسين الأداء.
    • على سبيل المثال:
       CREATE INDEX idx_empleados_salario ON empleados (salario) WHERE salario IS NOT NULL;
      

الممارسات الجيدة عند استخدام Have

  1. استخدم أسماء الأعمدة الوصفية والأسماء المستعارة:
    • قم بتعيين أسماء وصفية للأعمدة والأسماء المستعارة في جملة SELECT لتحسين قابلية قراءة الاستعلام.
    • استخدم أسماء تعكس بوضوح الغرض أو محتوى كل عمود أو تعبير.
    • على سبيل المثال:
       SELECT departamento, COUNT(*) AS total_empleados, AVG(salario) AS salario_promedio
      FROM empleados
      GROUP BY departamento
      HAVING AVG(salario) > 5000;
      
  2. اكتب الشروط واضحة وموجزة:
    • اكتب شروطًا واضحة وموجزة في البند Have لجعل الكود الخاص بك أسهل للفهم والصيانة.
    • تجنب الشروط المعقدة أو المتداخلة بشكل مفرط، وفكر في تقسيم الاستعلام إلى أجزاء أصغر وأكثر قابلية للإدارة إذا لزم الأمر.
    • على سبيل المثال:
       HAVING COUNT(DISTINCT categoria) > 3 AND SUM(total_ventas) > 10000;
      
  3. استخدم وظائف التجميع المناسبة:
    • قم باختيار وظائف التجميع المناسبة استنادًا إلى احتياجاتك ونوع بيانات الأعمدة.
    • استخدم COUNT(*) لحساب جميع الصفوف، بما في ذلك تلك التي تحتوي على قيم فارغة.
    • يستخدم COUNT(column) لحساب الصفوف حيث لا يحتوي العمود المحدد على قيمة فارغة.
    • استخدم SUM، وAVG، وMAX، وMIN حسب الحاجة لإجراء الحسابات التجميعية.
    • على سبيل المثال:
       HAVING COUNT(*) > 100 AND AVG(precio) < 50;
      
  4. قم بتطبيق المرشحات في شرط WHERE كلما أمكن ذلك:
    • إذا كان بإمكانك تصفية الصفوف الفردية قبل التجميع باستخدام شرط WHERE، فافعل ذلك لتقليل كمية البيانات التي تتم معالجتها في شرط Having.
    • قد يؤدي تصفية الصفوف قبل التجميع إلى تحسين أداء الاستعلام.
    • على سبيل المثال:
       SELECT categoria, SUM(total_ventas) AS total_ventas
      FROM ventas
      WHERE fecha >= '2023-01-01' AND fecha < '2024-01-01'
      GROUP BY categoria
      HAVING SUM(total_ventas) > 10000;
      
  5. استخدم الاستعلامات الفرعية أو الجداول المشتقة عند الضرورة:
    • إذا كنت بحاجة إلى إجراء حسابات معقدة أو تصفية استنادًا إلى نتائج مجمعة، ففكر في استخدام الاستعلامات الفرعية أو الجداول المشتقة.
    • يمكن أن تعمل الاستعلامات الفرعية والجداول المشتقة على تحسين قابلية القراءة والأداء في الاستعلامات المعقدة.
    • على سبيل المثال:
       SELECT *
      FROM (
          SELECT categoria, SUM(total_ventas) AS total_ventas
          FROM ventas
          GROUP BY categoria
      ) AS subconsulta
      WHERE total_ventas > (SELECT AVG(total_ventas) FROM ventas);
      
  6. وثّق الكود الخاص بك وعلّق عليه:
    • أضف تعليقات واضحة وموجزة لشرح الغرض والمنطق للأجزاء المختلفة من استعلامك، وخاصة في جملة Have.
    • إن التوثيق المناسب يجعل من الأسهل بالنسبة للمطورين الآخرين ونفسك فهم الكود الخاص بك وصيانته في المستقبل.
    • على سبيل المثال:
       -- Obtener las categorías con un total de ventas superior al promedio
      SELECT categoria, SUM(total_ventas) AS total_ventas
      FROM ventas
      GROUP BY categoria
      HAVING SUM(total_ventas) > (SELECT AVG(total_ventas) FROM ventas);
      
  7. قم بإجراء اختبارات مكثفة:
    • اختبر استعلاماتك باستخدام مجموعات بيانات وحالات اختبار مختلفة.
    • تأكد من أن النتائج التي تم الحصول عليها هي كما هو متوقع وأن الاستعلام يتصرف بشكل صحيح في السيناريوهات المختلفة، بما في ذلك الحالات الحدية والبيانات الفارغة.
    • استخدم أدوات تحليل الأداء وتصحيح الأخطاء لتحديد المشكلات واستكشاف الأخطاء وإصلاحها.
    • على سبيل المثال:
       -- Prueba con diferentes umbrales de total de ventas
      HAVING SUM(total_ventas) > 10000;
      HAVING SUM(total_ventas) > 50000;
      HAVING SUM(total_ventas) > 100000;
      
  8. خذ في الاعتبار الأداء والتحسين:
    • ضع الأداء في الاعتبار عند كتابة الاستعلامات باستخدام Having، خاصةً على مجموعات البيانات الكبيرة.
    • استخدم الفهارس المناسبة على الأعمدة المستخدمة في جملة GROUP BY وHaving الشروط لتحسين سرعة الاستعلام.
    • تجنب الحسابات غير الضرورية أو المكررة في جملة Have.
    • على سبيل المثال:
       -- Utiliza índices en las columnas de agrupación y filtrado
      CREATE INDEX idx_ventas_categoria ON ventas (categoria);
      CREATE INDEX idx_ventas_fecha ON ventas (fecha);
      
  9. الحفاظ على الاتساق والتوحيد القياسي:
    • اتبع اتفاقيات التسمية والتنسيق المتسقة في جميع استعلاماتك باستخدام Having.
    • استخدم أسلوب ترميز متسق، مثل كتابة الكلمات الرئيسية بأحرف كبيرة والمسافة البادئة المناسبة.
    • الحفاظ على الاتساق في بنية الاستعلام وترتيب البنود.
    • على سبيل المثال:
       SELECT categoria, SUM(total_ventas) AS total_ventas
      FROM ventas
      WHERE fecha >= '2023-01-01' AND fecha < '2024-01-01'
      GROUP BY categoria
      HAVING SUM(total_ventas) > 10000
      ORDER BY total_ventas DESC;
      
  10. ابق على اطلاع وتعلم من المجتمع:
    • ابق على اطلاع بأحدث ميزات MySQL والتحسينات المتعلقة بالأداء وتحسين الاستعلامات.
    • تعلم من مجتمع المطورين وشارك معرفتك وخبراتك.
    • المشاركة في المنتديات والمدونات والمؤتمرات لتعلم أفضل الممارسات والبقاء على اطلاع بأحدث الاتجاهات.
    • على سبيل المثال:
    • اتبع المدونات والموارد عبر الإنترنت حول الاستفسارات.
    • المشاركة في مجتمعات المطورين وطرح الأسئلة في المنتديات المتخصصة.
    • حضور المؤتمرات والندوات عبر الإنترنت حول MySQL وقواعد البيانات.
  11. التواجد في الاستعلامات مع الترقيم والفرز

    1. الترقيم الصفحي باستخدام LIMIT و OFFSET:
      • يسمح لك التقسيم إلى صفحات بتقسيم نتائج الاستعلام إلى صفحات أصغر وأكثر قابلية للإدارة.
      • استخدم البند LIMIT لتحديد الحد الأقصى لعدد الصفوف المراد إرجاعها والبند OFFSET لتحديد عدد الصفوف المراد تخطيها قبل البدء في إرجاع النتائج.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING SUM(total_ventas) > 10000
        ORDER BY total_ventas DESC
        LIMIT 10 OFFSET 0;
        
    2. الفرز حسب الترتيب:
      • يتم استخدام شرط ORDER BY لترتيب نتائج الاستعلام وفقًا لعمود واحد أو أكثر.
      • يمكنك فرز النتائج حسب الترتيب التصاعدي (ASC) أو التنازلي (DESC).
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING SUM(total_ventas) > 10000
        ORDER BY total_ventas DESC;
        
    3. التفاعل بين Having وORDER BY وLimit:
      • من المهم ملاحظة الترتيب الذي يتم به تطبيق جمل Having، وORDER BY، وLIMIT.
      • يتم تطبيق شرط Have أولاً لتصفية مجموعات الصفوف التي تلبي الشرط المحدد.
      • يتم بعد ذلك تطبيق شرط ORDER BY لفرز النتائج التي تمت تصفيتها.
      • أخيرًا، يتم تطبيق جملتي LIMIT وOFFSET لتحديد عدد الصفوف التي تم إرجاعها وتقسيم النتائج إلى صفحات.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING SUM(total_ventas) > 10000
        ORDER BY total_ventas DESC
        LIMIT 10 OFFSET 20;
        
    4. اعتبارات الأداء:
      • عند العمل مع مجموعات كبيرة من البيانات واستخدام الترقيم والفرز جنبًا إلى جنب مع Have، من المهم مراعاة أداء الاستعلام.
      • تأكد من أن لديك الفهارس المناسبة للأعمدة المستخدمة في شرط GROUP BY، ووجود الشروط، وفرز الأعمدة لتحسين كفاءة الاستعلام.
      • ضع في اعتبارك أن ملف خادم قاعدة البيانات يتعين عليك معالجة كافة النتائج وفرزها قبل تطبيق LIMIT وOFFSET، مما قد يؤثر على الأداء على مجموعات البيانات الكبيرة جدًا.
      • فكر في استخدام تقنيات الترقيم الصفحي الأكثر تقدمًا، مثل الترقيم الصفحي المستند إلى المؤشر أو الترقيم الصفحي باستخدام المفاتيح الأساسية، لتحسين الأداء في حالات معينة.
    5. الترقيم والفرز في التطبيقات:
      • عند تطوير التطبيقات التي تتطلب الترقيم والفرز إلى جانب Have، من المهم تصميم استراتيجية مناسبة للتعامل مع هذه الجوانب بكفاءة.
      • استخدم المعلمات في استعلاماتك للسماح بالترقيم الديناميكي والفرز استنادًا إلى تفضيلات المستخدم.
      • خذ في الاعتبار تخزين النتائج المصنفة والمقسمة إلى صفحات مؤقتة لتجنب الاستعلامات المتكررة وتحسين الأداء.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING SUM(total_ventas) > ? 
        ORDER BY ? ?
        LIMIT ? OFFSET ?;
        

    متقدم باستخدام Have مع الاستعلامات الفرعية

    1. تصفية المجموعات استنادًا إلى نتائج الاستعلام الفرعي المجمعة:
      • يمكنك استخدام الاستعلامات الفرعية في البند Having لتصفية المجموعات استنادًا إلى النتائج المجمعة لاستعلام آخر.
      • يعد هذا مفيدًا عندما تحتاج إلى مقارنة القيم الإجمالية لكل مجموعة بقيمة محسوبة في استعلام فرعي.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING SUM(total_ventas) > (
            SELECT AVG(total_ventas)
            FROM (
                SELECT categoria, SUM(total_ventas) AS total_ventas
                FROM ventas
                GROUP BY categoria
            ) AS subconsulta
        );
        
    2. تصفية المجموعات بناءً على وجود صفوف في استعلام فرعي:
      • يمكنك استخدام جملة EXISTS مع ضرورة تصفية المجموعات استنادًا إلى وجود صفوف في استعلام فرعي ذي صلة.
      • يعد هذا مفيدًا عندما تريد الاحتفاظ فقط بتلك المجموعات التي لها علاقة محددة بنتائج الاستعلام الفرعي.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING EXISTS (
            SELECT 1
            FROM productos
            WHERE productos.categoria = ventas.categoria
            AND productos.precio > 100
        );
        
    3. تصفية المجموعات بناءً على العضوية في مجموعة من القيم:
      • يمكنك استخدام جملة IN بالاشتراك مع جملة Haven لتصفية المجموعات بناءً على عضويتها في مجموعة من القيم التي تم الحصول عليها من استعلام فرعي.
      • يعد هذا مفيدًا عندما تريد الاحتفاظ فقط بتلك المجموعات التي تتطابق قيمها الإجمالية مع القيم المحددة في الاستعلام الفرعي.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING categoria IN (
            SELECT categoria
            FROM productos
            WHERE precio > 100
        );
        
    4. تصفية المجموعات بناءً على المقارنة بالقيم الدنيا أو القصوى:
      • يمكنك استخدام الاستعلامات الفرعية الموجودة في البند Have لتصفية المجموعات بناءً على المقارنة مع الحد الأدنى أو الحد الأقصى للقيم التي تم الحصول عليها من استعلام آخر.
      • يعد هذا مفيدًا عندما تريد الاحتفاظ فقط بتلك المجموعات التي تلبي قيمها الإجمالية معايير معينة فيما يتعلق بالقيم المتطرفة.
      • على سبيل المثال:
         SELECT categoria, SUM(total_ventas) AS total_ventas
        FROM ventas
        GROUP BY categoria
        HAVING SUM(total_ventas) > (
            SELECT MAX(total_ventas)
            FROM (
                SELECT categoria, SUM(total_ventas) AS total_ventas
                FROM ventas
                GROUP BY categoria
            ) AS subconsulta
            WHERE categoria <> ventas.categoria
        );
        

    تحسين الأداء باستخدام الفهارس والأقسام

    1. استخدام الفهارس في تجميع الأعمدة:
      • إنشاء فهارس على الأعمدة المستخدمة في البند GROUP BY لتحسين كفاءة التجميع.
      • تسمح الفهارس لـ MySQL بتحديد الصفوف التي تنتمي إلى كل مجموعة بسرعة، مما يؤدي إلى تسريع عملية التجميع.
      • على سبيل المثال:
         CREATE INDEX idx_ventas_categoria ON ventas (categoria);
        
    2. استخدام الفهارس على أعمدة التصفية:
      • قم بإنشاء فهارس على الأعمدة المستخدمة في شروط جملة Having لتحسين سرعة التصفية.
      • تسمح الفهارس لـ MySQL بالعثور بسرعة على الصفوف التي تلبي الشروط المحددة في Having.
      • على سبيل المثال:
         CREATE INDEX idx_ventas_total ON ventas (total_ventas);
        
    3. استخدام المؤشرات المركبة:
      • إنشاء فهارس مركبة تتضمن أعمدة التجميع وأعمدة التصفية.
      • يمكن أن تعمل الفهارس المركبة على تحسين الأداء بشكل أكبر من خلال السماح لـ MySQL بإجراء عمليات بحث وتصفية فعالة باستخدام فهرس واحد.
      • على سبيل المثال:
         CREATE INDEX idx_ventas_categoria_total ON ventas (categoria, total_ventas);
        
    4.  CREATE TABLE ventas (
      id INT,
      categoria VARCHAR(50),
      total_ventas DECIMAL(10,2),
      fecha DATE
      )
      PARTITION BY HASH(YEAR(fecha))
      PARTITIONS 5;
      

      التواجد في بيئات ذات تزامن عالي