سؤال

غالبًا ما تحتاج إلى إظهار قائمة بعناصر قاعدة البيانات وأرقام مجمعة معينة حول كل عنصر.على سبيل المثال، عند كتابة نص العنوان في Stack Overflow، تظهر قائمة الأسئلة ذات الصلة.تعرض القائمة عناوين الإدخالات ذات الصلة والعدد المجمع الفردي لكمية الردود لكل عنوان.

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

  • اسم العنصر الخاص بي (إجمالي 15، 13 مملوكة لي)
  • اسم العنصر الخاص بي (إجمالي 15)
  • اسم السلعة الخاصة بي (13 مملوكة لي)

قاعدة البيانات الخاصة بي هي:

  • أغراض:معرف العنصر، اسم العنصر، معرف المالك
  • فئات:معرف القط، اسم القط
  • خريطة:معرف الخريطة، معرف العنصر، معرف القط

الاستعلام أدناه يحصل على:اسم الفئة، عدد معرفات العناصر لكل فئة

SELECT
  categories.catName,
  COUNT(map.itemId) AS item_count
FROM categories
LEFT JOIN map
  ON categories.catId = map.catId
GROUP BY categories.catName

هذا واحد يحصل على:اسم الفئة، عدد معرفات العناصر لكل فئة لمعرف_المالك هذا فقط

SELECT categories.catName, 
COUNT(map.itemId) AS owner_item_count
FROM categories
LEFT JOIN map
  ON categories.catId = map.catId
LEFT JOIN items
  ON items.itemId = map.itemId
WHERE owner = @ownerId
GROUP BY categories.catId

ولكن كيف يمكنني الحصول عليها في نفس الوقت في استعلام واحد؟أي.:اسم الفئة، عدد معرفات العناصر لكل فئة، عدد معرفات العناصر لكل فئة لمعرف_المالك هذا فقط

علاوة.كيف يمكنني اختياريًا استرداد رقم catId فقط!= 0 لأي من هذه العناصر؟في تجربة "WHERE item_count <> 0" أحصل على:

MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause' 
هل كانت مفيدة؟

المحلول

إليك خدعة:حساب أ SUM() من القيم المعروفة بأنها إما 1 أو 0 تعادل a COUNT() من الصفوف التي تكون القيمة فيها 1.وأنت تعلم أن المقارنة المنطقية ترجع 1 أو 0 (أو NULL).

SELECT c.catname, COUNT(m.catid) AS item_count,
  SUM(i.ownerid = @ownerid) AS owner_item_count
FROM categories c
  LEFT JOIN map m USING (catid)
  LEFT JOIN items i USING (itemid)
GROUP BY c.catid;

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

SELECT c.catname, COUNT(m.catid) AS item_count,
  SUM(i.ownerid = @ownerid) AS owner_item_count
FROM categories c
  INNER JOIN map m USING (catid)
  INNER JOIN items i USING (itemid)
GROUP BY c.catid;

إليك حل آخر، وهو ليس بنفس الكفاءة ولكنني سأعرضه لتوضيح سبب حصولك على الخطأ:

SELECT c.catname, COUNT(m.catid) AS item_count,
  SUM(i.ownerid = @ownerid) AS owner_item_count
FROM categories c
  LEFT JOIN map m USING (catid)
  LEFT JOIN items i USING (itemid)
GROUP BY c.catid
HAVING item_count > 0;

لا يمكنك استخدام الأسماء المستعارة للأعمدة في WHERE الشرط، لأن التعبيرات في WHERE يتم تقييم الجملة قبل التعبيرات الموجودة في قائمة التحديد.بمعنى آخر، القيم المرتبطة بتعبيرات قائمة التحديد غير متوفرة بعد.

يمكنك استخدام الأسماء المستعارة للأعمدة في GROUP BY, HAVING, ، و ORDER BY شروط.يتم تشغيل هذه الجمل بعد تقييم جميع التعبيرات الموجودة في قائمة التحديد.

نصائح أخرى

يمكنك التسلل إلى عبارة CASE داخل SUM() الخاص بك:

SELECT categories.catName, 
    COUNT(map.itemId) AS item_count,
    SUM(CASE WHEN owner= @ownerid THEN 1 ELSE 0 END) AS owner_item_count
FROM categories
LEFT JOIN map  ON categories.catId = map.catId
LEFT JOIN items  ON items.itemId = map.itemId
GROUP BY categories.catId
HAVING COUNT(map.itemId) > 0
SELECT categories.catName, 
  COUNT(map.itemId) AS item_count,
  COUNT(items.itemId) AS owner_item_count
FROM categories
INNER JOIN map
  ON categories.catId = map.catId
LEFT JOIN items
  ON items.itemId = map.itemId
  AND items.owner = @ownerId
GROUP BY categories.catId

لاحظ أنه يمكنك استخدام أ HAVING شرط على owner_item_count, ، ولكن الصلة الداخلية تعتني بـ item_count نيابةً عنك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top