Reputation: 5044
I currently use the following query which works perfectly:
SELECT * FROM `items` WHERE `id` IN
(SELECT `item_id` FROM `categories_items`
WHERE `category_id` IN (1, 2) GROUP BY `item_id`
HAVING COUNT(`item_id`) = 2);
It selects all the items that are in all the selected (checkboxes) categories.
The problem is that most items are in many categories and a few items are only in two categories and when I only check those two, I still get a list of hundreds of items, making it nearly impossible to find the items that are in few categories.
My first idea was to add an ORDER BY "number_of_total_categories_that_the_selected_item_is_in" ASC
somewhere in the query, but since I even got help with the current one and there would probably be a lot of calculations/subqueries for it to work, I thought of an extra column in the items
table that would hold the number of categories it's in!
If not, all I can think of is to manually update a category_count
column in items
whenever it's needed.
Edit: Table field that holds row count from another table looks interesting, but I have no idea whether it would work in MySQL.
Upvotes: 0
Views: 301
Reputation: 1271151
You want to use join
rather than in
. The following query filters for items that only have the two categories you want. It also counts the total number of categories, which can be used for the order by
:
SELECT i.*
FROM `items` i JOIN
(SELECT `item_id`, COUNT(*) as cnt
FROM `categories_items`
WHERE `category_id` IN (1, 2)
GROUP BY `item_id`
HAVING COUNT(DISTINCT CASE WHEN category_id IN (1, 2) THEN category_id END) = 2
) c
ON i.id = c.item_id
ORDER BY cnt ASC;
EDIT:
If you want to count all the categories, then get rid of the where
. It is not really doing anything:
SELECT i.*
FROM `items` i JOIN
(SELECT `item_id`, COUNT(*) as cnt
FROM `categories_items`
GROUP BY `item_id`
HAVING COUNT(DISTINCT CASE WHEN category_id IN (1, 2) THEN category_id END) = 2
) c
ON i.id = c.item_id
ORDER BY cnt ASC;
Upvotes: 1