Frage

Stellen Sie sich die folgenden Tabellen:

Tabellenfelder erstellen (id int, namenstext, ...);

Tabelle thingsinboxes (id int, int box_id, was ENUM ( 'Apfel' Banane‘, 'Orange') schaffen;

Und die Tabellen wie folgt aussehen:

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

Wie wähle ich die Boxen, die mindestens eine orange und nichts enthalten, die nicht eine Orange ist?

Wie funktioniert diese Skala, vorausgesetzt, ich mehrere hunderttausend Kisten und möglicherweise eine Million Dinge in Kisten?

Ich möchte das alles, wenn möglich in SQL halten, anstatt Nachverarbeitung das Ergebnis mit einem Skript festgelegt.

ich beide Postgres und MySQL bin mit, so Subqueries wahrscheinlich schlecht ist, da MySQL optimiert nicht Subqueries (pre-Version 6, sowieso).

War es hilfreich?

Lösung

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;

Hier ist eine andere Lösung, die nicht GROUP BY nicht verwendet:

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;

Wie immer, bevor Sie Rückschlüsse auf die Skalierbarkeit oder Leistung einer Abfrage machen, Sie haben es versuchen mit einem realistischen Datensatz und die Leistung messen.

Andere Tipps

ich denke, Bill Karwin Abfrage nur in Ordnung, aber wenn ein relativ geringer Anteil von Kisten Orangen enthält, sollten Sie in der Lage sein, die Dinge, indem Sie einen Index für das thing Feld zu beschleunigen:

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

Die WHERE NOT EXISTS Unterabfrage wird nur einmal pro Orange Sache betrieben werden, so ist es nicht zu teuer vorausgesetzt, es gibt nicht viele Orangen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top