I have a SELECT statement that works, and runs fast enough on my tables (<0.01sec on 50k+ products, 3k+ categories). But in my mind it’s not very elegant and would like to hear any suggestions on making it better.
There are 3 tables of interest:
- products – key productID
- categories – key categoryID
- products_tree – link table (categories contain many products, products can belong to many categories)
I have a list of excluded categoryIDs [e.g. 1040,1050,1168] I want to select all the productIDs that belong to one of these excluded categories only if the product doesn’t belong to another NON-excluded category
My Query looks like this:
SELECT DISTINCT productID FROM products_tree WHERE categoryID IN (1040,1050,1168) AND productID NOT IN ( SELECT DISTINCT productID FROM products_tree WHERE categoryID NOT IN (1040,1050,1168) );
I can think of a few methods, each of which perform differently depending on indexes and your particular database implementation. Some that may look slow can be optimised in ways you may not have imagined and so it’s worth trialling them all and comparing execution plans to see what is happening…
Note1: I use GROUP BY rather than DISTINCT, this is because it allows the omptimiser to make use of indexes. I’ve seen implementations work out that they can turn the DISTINCT in to a GROUP BY, but it’s highly worth using GROUP BY in the fist place to be sure. It also gets you thinking about indexes, which is never a bad thing.
Note2: Some queries like this take a while to optimise, as there are many options for the optimiser to evaluate. It is therefore often worth compiling all the different options in to stored procedures and comparing the execution of those stored procedures. This ensures your compare actually Query Time and not different Compile Times.
There are others, and variations of each, but this should give you a very good start. But I really would stress the use of GROUP BY and the consideration to INDEXES 🙂