قم بتصفية استعلام واحد إلى أقصى
-
20-08-2019 - |
سؤال
تخيل الجداول التالية:
إنشاء مربعات الجدول (معرف int ، نص الاسم ، ...) ؛
قم بإنشاء Table ThingsInboxes (ID int ، box_id int ، thing enum ('Apple ،' Banana '،' Orange ') ؛
والجداول تبدو مثل:
Boxes: id | name 1 | orangesOnly 2 | orangesOnly2 3 | orangesBananas 4 | misc thingsinboxes: id | box_id | thing 1 | 1 | orange 2 | 1 | orange 3 | 2 | orange 4 | 3 | orange 5 | 3 | banana 6 | 4 | orange 7 | 4 | apple 8 | 4 | banana
كيف يمكنني اختيار الصناديق التي تحتوي على برتقالي واحد على الأقل ولا شيء ليس برتقاليًا؟
كيف هذا النطاق ، على افتراض أن لدي عدة مئات من الآلاف من الصناديق وربما مليون شيء في الصناديق؟
أرغب في الحفاظ على كل هذا في SQL إن أمكن ، بدلاً من معالجة ما بعد المعالجة.
أنا أستخدم كل من Postgres و MySQL ، لذلك من المحتمل أن تكون الفخات الفرعية سيئة ، بالنظر إلى أن MySQL لا يحسن الفوز الفرعي (Pre Pred 6 ، على أي حال).
المحلول
SELECT b.*
FROM boxes b JOIN thingsinboxes t ON (b.id = t.box_id)
GROUP BY b.id
HAVING COUNT(DISTINCT t.thing) = 1 AND SUM(t.thing = 'orange') > 0;
إليك حل آخر لا يستخدم المجموعة بواسطة:
SELECT DISTINCT b.*
FROM boxes b
JOIN thingsinboxes t1
ON (b.id = t1.box_id AND t1.thing = 'orange')
LEFT OUTER JOIN thingsinboxes t2
ON (b.id = t2.box_id AND t2.thing != 'orange')
WHERE t2.box_id IS NULL;
كما هو الحال دائمًا ، قبل إجراء استنتاجات حول قابلية التوسع أو أداء الاستعلام ، عليك أن تجربها مع مجموعة بيانات واقعية ، وقياس الأداء.
نصائح أخرى
أعتقد أن استعلام بيل كاروين على ما يرام ، ولكن إذا كانت نسبة صغيرة نسبيًا من الصناديق تحتوي على برتقال ، فيجب أن تكون قادرًا على تسريع الأمور باستخدام فهرس على thing
مجال:
SELECT b.*
FROM boxes b JOIN thingsinboxes t1 ON (b.id = t1.box_id)
WHERE t1.thing = 'orange'
AND NOT EXISTS (
SELECT 1
FROM thingsinboxes t2
WHERE t2.box_id = b.id
AND t2.thing <> 'orange'
)
GROUP BY t1.box_id
ال WHERE NOT EXISTS
لن يتم تشغيل الاسعة الفرعي إلا مرة واحدة لكل شيء برتقالي ، لذلك ليس مكلفًا للغاية بشرط ألا يكون هناك العديد من البرتقال.