Domanda

Immagina le seguenti tabelle:

crea caselle di tabella (id int, nome testo, ...);

crea oggetti da tavolo (id int, box_id int, thing enum ('apple,' banana ',' orange ');

E le tabelle sembrano:

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

Come seleziono le caselle che contengono almeno un'arancia e niente che non sia un'arancia?

In che modo questa scala, supponendo che io abbia diverse centinaia di migliaia di scatole e forse un milione di cose in scatole?

Vorrei mantenere tutto questo in SQL, se possibile, piuttosto che post-elaborazione del set di risultati con uno script.

Sto usando sia Postgres che MySQL, quindi le sottoquery sono probabilmente pessime, dato che mysql non ottimizza le subquery (pre-versione 6, comunque).

È stato utile?

Soluzione

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;

Ecco un'altra soluzione che non utilizza GROUP BY:

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;

Come sempre, prima di trarre conclusioni sulla scalabilità o sulle prestazioni di una query, devi provarla con un set di dati realistico e misurare le prestazioni.

Altri suggerimenti

Penso che la query di Bill Karwin vada bene, tuttavia se una percentuale relativamente piccola di scatole contiene arance, dovresti essere in grado di velocizzare le cose usando un indice nel campo 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

La sottoquery WHERE NOT EXISTS verrà eseguita una sola volta per dispositivo arancione, quindi non è troppo costosa a condizione che non ci siano molte arance.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top